node.js, mongodb, redis, pada penurunan kinerja ubuntu dalam produksi, RAM gratis, CPU 100%

11

Seperti yang disarankan judul pertanyaan, saya mengalami kesulitan untuk mencari tahu apa yang dapat ditingkatkan pada aplikasi saya (atau dicari di os, ubuntu) untuk mencapai kinerja yang dapat diterima. Tapi pertama-tama saya akan menjelaskan arsitekturnya:

Server front-end adalah mesin 8 inti dengan 8 gigs RAM yang menjalankan Ubuntu 12.04. Aplikasi ini ditulis seluruhnya dalam javascript dan dijalankan di node.js v 0.8.22 (karena beberapa modul tampaknya mengeluh pada versi yang lebih baru dari node) Saya menggunakan nginx 1.4 untuk mem-proxy lalu lintas http dari port 80 dan 443 hingga 8 pekerja simpul yang dikelola dan mulai menggunakan simpul cluster api. Saya menggunakan versi socket.io 0.9.14 terbaru untuk menangani koneksi websocket, di mana saya hanya mengaktifkan soket web dan xhr-polling sebagai transport yang tersedia. Di mesin ini saya juga menjalankan instance Redis (2.2)

Saya menyimpan data persisten (seperti pengguna dan skor) pada server kedua di mongodb (3,6) dengan RAM 4gigs dan 2 core.

Aplikasi ini dalam produksi sejak beberapa bulan (itu berjalan pada satu kotak sampai beberapa minggu yang lalu) dan sedang digunakan oleh sekitar 18k pengguna per hari. Itu selalu bekerja dengan sangat baik terlepas dari satu masalah utama: penurunan kinerja. Dengan penggunaan, jumlah cpu yang digunakan oleh setiap proses tumbuh sampai membuat pekerja menjadi lebih matang (yang tidak lagi melayani permintaan). Saya sementara waktu menyelesaikannya memeriksa cpu yang digunakan oleh setiap pekerja setiap menit, dan memulai kembali jika mencapai 98%. Jadi masalahnya di sini adalah cpu, dan bukan RAM. RAM bukan masalah lagi karena saya telah memperbarui ke socket.io 0.9.14 (versi sebelumnya adalah memori bocor) jadi saya ragu itu menjadi masalah kebocoran memori, terutama karena sekarang cpu yang tumbuh cukup cepat ( Saya harus memulai kembali setiap pekerja sekitar 10-12 kali sehari!). RAM yang digunakan tumbuh juga jujur, tapi sangat lambat, 1 manggung setiap 2-3 hari penggunaan, dan yang aneh adalah itu tidak dirilis bahkan ketika saya me-restart seluruh aplikasi. Ini hanya dirilis jika saya me-reboot server! ini saya tidak bisa mengerti ...

Saya sekarang telah menemukan nodefly yang luar biasa, jadi saya akhirnya bisa melihat apa yang terjadi di server produksi saya, dan saya mengumpulkan data sejak beberapa hari. Jika ada yang ingin melihat grafik saya dapat memberi Anda akses, tetapi pada dasarnya saya dapat melihat bahwa saya memiliki antara 80 dan 200 koneksi bersamaan! Saya mengharapkan node.js untuk menangani ribuan, bukan ratusan permintaan. Juga waktu respon rata-rata untuk lalu lintas http mengapung antara 500 dan 1500 milidetik yang menurut saya sangat banyak. Juga, saat ini dengan 1300 pengguna online, ini adalah output dari "ss -s":

Total: 5013 (kernel 5533)
TCP:   8047 (estab 4788, closed 3097, orphaned 139, synrecv 0, timewait 3097/0), ports 0

Transport Total     IP        IPv6
*         5533      -         -
RAW       0         0         0
UDP       0         0         0
TCP       4950      4948      2
INET      4950      4948      2
FRAG      0         0         0

yang menunjukkan bahwa saya punya banyak koneksi tertutup di timewait. Saya telah meningkatkan file max terbuka ke 999999, di sini adalah output dari ulimit -a:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63724
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 999999
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63724
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Jadi saya pikir masalahnya mungkin pada lalu lintas http yang karena beberapa alasan memenuhi port / soket yang tersedia (?), Tetapi satu hal tidak masuk akal bagi saya: mengapa ketika saya me-restart pekerja, dan semua klien terhubung kembali dalam beberapa detik, beban cpu pekerja turun ke 1% dan mampu melayani permintaan dengan benar sampai jenuh setelah sekitar 1 jam (pada waktu puncak)?

Saya terutama seorang programmer javascript, bukan admin sys jadi saya tidak tahu berapa banyak beban yang saya harapkan untuk ditangani dengan server saya, tapi tentu saja itu tidak berkinerja sebagaimana mestinya. Aplikasi ini stabil jika tidak dan masalah terakhir ini mencegah saya untuk mengirimkan versi mobile dari aplikasi yang siap, karena jelas mereka akan membawa lebih banyak beban dan akhirnya menabrak semuanya!

Mudah-mudahan ada sesuatu yang jelas bahwa saya melakukan kesalahan, dan seseorang akan membantu untuk menemukannya ... jangan ragu untuk meminta saya untuk info lebih lanjut, dan saya minta maaf untuk panjang pertanyaan tetapi perlu saya percaya ... Terima kasih sebelumnya!

Franjanko
sumber
Apakah ada cara untuk mendapatkan sesuatu seperti thread dump dari node.js? Mungkin ada beberapa utas dalam loop tak terbatas. Juga, apa yang sebenarnya menggunakan cpu? Apa yang Anda lihat topketika penggunaan cpu mendekati 100%?
rvs
cpu digunakan sepenuhnya oleh nodejs, ketika saya menjalankan top saya melihat proses node mengambil semua cpu. Tidak yakin bagaimana saya bisa menampilkan thread dump dari node menjadi jujur ​​...
Franjanko
Satu hal lagi yang perlu
diperhatikan
Adakah yang setidaknya tahu berapa banyak koneksi konkuren yang harus saya bisa tangani dengan server yang saya miliki? saat ini saya mendukung 200 koneksi konkursi maks. Ini akan membantu saya memperkirakan seberapa jauh saya dari konfigurasi optimal ... terima kasih.
Franjanko

Jawaban:

10

Setelah beberapa hari menjalani percobaan dan kesalahan yang intens, saya senang dapat mengatakan bahwa saya telah memahami di mana hambatannya, dan saya akan mempostingnya di sini sehingga orang lain dapat memperoleh manfaat dari temuan saya.

Masalahnya terletak pada koneksi pub / sub yang saya gunakan dengan socket.io, dan khususnya di RedisStore digunakan oleh socket.io untuk menangani komunikasi antar-proses instance socket.

Setelah menyadari bahwa saya dapat mengimplementasikan versi pub / sub saya sendiri dengan menggunakan redis, saya memutuskan untuk mencobanya, dan menghapus redisStore dari socket.io, meninggalkannya dengan penyimpanan memori default (saya tidak perlu menyiarkan ke semua klien yang terhubung tetapi hanya antara 2 pengguna yang berbeda yang terhubung mungkin pada proses yang berbeda)

Awalnya saya menyatakan hanya 2 koneksi redis global x proses untuk menangani pub / sub pada setiap klien yang terhubung, dan aplikasi menggunakan lebih sedikit sumber daya tetapi saya masih dipengaruhi oleh pertumbuhan penggunaan CPU yang konstan, jadi tidak banyak yang berubah. Tapi kemudian saya memutuskan untuk mencoba membuat 2 koneksi baru untuk redis bagi setiap klien untuk menangani pub / sub mereka hanya pada sesi mereka, kemudian tutup koneksi setelah pengguna terputus. Kemudian setelah satu hari digunakan dalam produksi, cpu masih 0-5% ... bingo! tidak ada proses restart, tidak ada bug, dengan kinerja yang saya harapkan untuk miliki. Sekarang saya bisa mengatakan simpul itu. Batu dan senang telah memilihnya untuk membangun aplikasi ini.

Untungnya redis telah dirancang untuk menangani banyak koneksi konkuren (berbeda dengan mongo) dan secara default diatur pada 10k, yang menyisakan ruang untuk sekitar 5k pengguna bersamaan, pada contoh redis tunggal, yang cukup untuk saat ini bagi saya, tetapi saya ' Telah membaca bahwa itu dapat didorong hingga 64k koneksi bersamaan, jadi arsitektur ini harus cukup solid saya percaya.

Pada titik ini saya sedang berpikir untuk menerapkan semacam kolam koneksi untuk redis, untuk mengoptimalkannya sedikit lebih jauh, tetapi saya tidak yakin apakah itu tidak akan menyebabkan lagi pub / sub acara menumpuk di koneksi, kecuali masing-masing dari mereka dihancurkan dan diciptakan kembali setiap kali, untuk membersihkannya.

Bagaimanapun, terima kasih atas jawaban Anda, dan saya akan penasaran untuk mengetahui apa yang Anda pikirkan, dan jika Anda memiliki saran lain.

Bersulang.

Franjanko
sumber
2
Saya mengalami masalah yang tampaknya sama di aplikasi produksi saya, juga baru di peran admin server. Saya mengikuti apa yang Anda lakukan dalam konsep, tetapi saya memiliki beberapa pertanyaan tentang bagaimana melakukannya - mungkin Anda bisa memberikan tautan ke beberapa sumber dalam jawaban yang Anda terima? Atau sekadar memberikan informasi lebih lanjut? Khususnya tentang "Tapi kemudian saya memutuskan untuk mencoba membuat 2 koneksi baru untuk redis bagi setiap klien untuk menangani pub / sub mereka hanya pada sesi mereka, lalu tutup koneksi setelah pengguna terputus."
toblerpwn
2

Apakah Anda memiliki beberapa kode sumber untuk dibuang? Mungkin koneksi ke basis data tidak ditutup? Proses menunggu koneksi HTTP yang tidak pernah ditutup.

Bisakah Anda memposting beberapa log?

Lakukan ps -ef dan pastikan tidak ada yang masih berjalan. Saya telah melihat proses web meninggalkan zombie yang tidak akan mati sampai Anda membunuh -9. Terkadang shutdown tidak berfungsi atau tidak berfungsi sepenuhnya dan utas atau proses tersebut akan menampung RAM dan terkadang CPU.

Ini bisa berupa infinite loop di suatu tempat dalam kode atau proses macet yang menahan koneksi db.

Modul NPM apa yang digunakan? Apakah semuanya terbaru?

Apakah Anda menangkap pengecualian? Lihat: http://geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ Lihat: /programming/10122245/capture-node-js-crash-reason

Tips Umum:

http://clock.co.uk/tech-blogs/preventing-http-raise-hangup-error-on-destroyed-socket-write-from-crashing-your-nodejs-server

http://blog.nodejitsu.com/keep-a-nodejs-server-up-with-forever

http://hectorcorrea.com/blog/running-a-node-js-web-site-in-production-a-beginners-guide

/programming/1911015/how-to-debug-node-js-applications

https://github.com/dannycoates/node-inspector

http://elegantcode.com/2011/01/14/taking-baby-steps-with-node-js-debugging-with-node-inspector/

Tim Spann
sumber
1

Bukan jawaban semata, karena pertanyaan Anda lebih merupakan dongeng daripada pertanyaan satu jawaban.

Hanya untuk mengatakan bahwa saya berhasil membangun server node.js dengan socket.io yang menangani lebih dari 1 juta koneksi persisten dengan rata-rata payload pesan 700 Bytes.

Kartu Antarmuka Jaringan pada 1Gbps jenuh pada awalnya, dan saya melihat BANYAK I / O menunggu dari mempublikasikan acara ke semua klien.

Menghapus nginx dari peran proxy juga telah mengembalikan memori yang berharga, karena untuk mencapai satu juta koneksi persisten hanya dengan SATU server, adalah pekerjaan yang sulit untuk mengubah konfigurasi, aplikasi, dan mengatur parameter OS. Perlu diingat bahwa itu hanya dapat dilakukan dengan banyak RAM (sekitar 1 juta koneksi soket memakan sekitar 16GB RAM, dengan node.js, saya pikir menggunakan sock.js akan ideal untuk konsumsi memori rendah, tetapi untuk sekarang, socket.io mengkonsumsi sebanyak itu).

Tautan ini adalah titik awal saya untuk mencapai volume koneksi dengan node tersebut. Selain sebagai aplikasi Erlang, semua tuning OS cukup banyak aplikasi agnostik dan harus digunakan oleh siapa saja yang bertujuan pada banyak koneksi persisten (websockets atau polling panjang).

HTH,

Marcel
sumber