node.js, mongodb, redis, üretimde ubuntu performansında bozulma, RAM ücretsiz, CPU 100%


11

Soru başlığının da belirttiği gibi, kabul edilebilir bir performans elde etmek için uygulamamda neyin geliştirilebileceğini (veya os, ubuntu'da ayarlanmış) anlamaya zorlanıyorum. Ama önce mimariyi açıklayacağım:

Ön uç sunucu, 8 çekirdekli RAM ile Ubuntu 12.04 çalıştıran 8 çekirdekli bir makinedir. Uygulama tamamen javascript ile yazılmış ve node.js v 0.8.22'de çalıştırılıyor (bazı modüller düğümün yeni sürümlerinden şikayet ediyor gibi) 80 ve 443 numaralı bağlantı noktasından http trafiğini yönetmek için nginx 1.4 kullanıyorum ve düğüm kümesi API'sini kullanmaya başladı. Ben sadece websockets ve xhr-polling'i kullanılabilir aktarımlar olarak etkinleştirdiğim websocket bağlantılarını işlemek için socket.io 0.9.14'ün en son sürümünü kullanıyorum. Bu makinede ayrıca Redis (2.2)

Kalıcı verileri (kullanıcılar ve skorlar gibi) 4gigs RAM ve 2 çekirdekli mongodb (3.6) üzerinde ikinci bir sunucuda saklıyorum.

Uygulama birkaç aydan beri üretiliyor (birkaç hafta öncesine kadar tek bir kutuda çalışıyor) ve günde yaklaşık 18 bin kullanıcı tarafından kullanılıyor. Her zaman bir ana konu dışında çok iyi çalıştı: performans bozulması. Kullanımla birlikte, her işlem tarafından kullanılan işlemci miktarı, çalışanı (bu artık istekleri karşılamayacak) statüye getirene kadar artar. Her işçi tarafından kullanılan cpu'yu her dakika kontrol etmeyi ve% 98'e ulaştığında yeniden başlatmayı geçici olarak çözdüm. Yani buradaki problem esas olarak CPU değil, RAM. RAM artık bir sorun değil, socket.io 0.9.14'e (önceki sürüm bellek sızdırıyor) güncellediğim için artık bir sorun değil, bu yüzden bir bellek sızıntısı sorunu olduğundan şüphe duyuyorum, çünkü özellikle şimdi oldukça hızlı büyüyen cpu ( Her çalışanı günde 10-12 kez yeniden başlatmalıyım!). Kullanılan RAM, dürüst olmak gerekirse büyüyor, ancak çok yavaş, her 2-3 günde bir 1 gig ve garip şey, tüm uygulamayı tamamen yeniden başlattığımda bile serbest bırakılmaması. Yalnızca sunucuyu yeniden başlatırsam yayınlanır! bunu gerçekten anlayamıyorum ...

Şimdi şaşırtıcı olan nodefly'i keşfettim , bu yüzden sonunda üretim sunucumda neler olduğunu görebiliyorum ve birkaç günden beri veri topluyorum. Eğer herkes grafikleri görmek istersen sana erişebilirim, ama temelde 80 ile 200 arasında eşzamanlı bağlantım olduğunu görebiliyorum! Node.js'nin yüzlerce isteği değil, binlerce kişiyi işlemesini bekliyordum. Ayrıca http trafik için ortalama tepki süresi gerçekten çok olduğunu düşünüyorum 500 ve 1500 milisaniye arasında yüzer. Ayrıca, şu anda çevrimiçi 1300 kullanıcı ile, bu "ss -s" çıktı:

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

Bu da zamana bağlı çok fazla kapalı bağlantım olduğunu gösteriyor. Maksimum açık dosyaları 999999'a çıkardım, işte ulimit -a çıktısı:

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

Bu nedenle, sorunun http trafiğinde, bazı nedenlerden dolayı mevcut bağlantı noktalarını / soketleri (?) Doyurduğunu düşündüm, ancak bir şey benim için anlamlı değil: neden işçileri yeniden başlattığımda ve tüm istemciler birkaç saniye içinde yeniden bağlandığında, işçinin cpu'sundaki yük% 1'e iner ve yaklaşık 1 saat sonra (en yoğun zamanda) doyuncaya kadar istekleri düzgün bir şekilde sunabilir mi?

Ben esas olarak bir javascript programcısı değilim, bir sys yöneticisi değilim, bu yüzden sunucularımla işlemek için ne kadar yük beklemem gerektiğini bilmiyorum, ama mutlaka olması gerektiği gibi performans göstermiyor. Aksi takdirde uygulama kararlı ve bu son sorun, açıkçası daha fazla yük getirecek ve sonunda her şeyi çökecek gibi hazır olan uygulamanın mobil sürümleri gemi beni engelliyor!

Umarım yanlış yaptığım açık bir şey vardır ve birisi bunu fark etmeye yardımcı olacaktır ... daha fazla bilgi istemekten çekinmeyin ve sorunun uzunluğu için özür dilerim ama gerekli olduğuna inanıyorum ... şimdiden teşekkürler!


Düğüm.js'den iplik dökümü gibi bir şey almanın bir yolu var mı? Sonsuz bir döngüde muhtemelen bazı iplikler vardır. Ayrıca, aslında cpu nedir? topİşlemci kullanımı% 100'e yakın olduğunda ne görüyorsunuz ?
rvs

cpu tamamen nodejs tarafından kullanılır, üstte çalıştırdığımda tüm cpu'yu alan düğüm süreçlerini görüyorum. Dürüst olmak gerekirse düğümden bir iplik dökümü nasıl çıktı emin değilim ...
Franjanko

başka bir şey CPU zamanının çoğunluğu kullanıcı zamanı değil, sisteme gidiyor gibi görünüyor
Franjanko

Herkes en az kaç tane eşzamanlı bağlantıyı yerine getirdiğim sunucularla başa çıkabileceğimi biliyor mu? şu anda maks. 200 eşzamanlı bağlantıyı destekliyorum. Bu, optimum bir yapılandırmadan ne kadar uzak olduğumu tahmin etmeme yardımcı olacak ... teşekkürler.
Franjanko

Yanıtlar:


10

Birkaç günlük yoğun deneme ve hatalardan sonra, darboğazın nerede olduğunu anladığımı söyleyebildiğim için memnunum ve diğer insanların bulgularımdan yararlanabilmesi için buraya göndereceğim.

Sorun, socket.io ile kullandığım pub / sub bağlantılarında ve özellikle soket örneklerinin süreçler arası iletişimini işlemek için socket.io tarafından kullanılan RedisStore'da yatıyor.

Redis'i kullanarak kendi pub / sub sürümümü kolayca uygulayabildiğimi fark ettikten sonra, denemeye karar verdim ve redisStore'u socket.io'dan varsayılan bellek deposuyla bıraktım (yayın yapmam gerekmiyor) bağlı istemcilerin tümü, ancak muhtemelen farklı süreçlere bağlı 2 farklı kullanıcı arasında)

Başlangıçta bağlı her istemcide pub / sub işlemek için sadece 2 global redis bağlantısı x süreci ilan ettim ve uygulama daha az kaynak kullanıyordu, ancak hala sabit bir CPU kullanım büyümesinden etkileniyordum, bu yüzden çok fazla değişmemişti. Ancak daha sonra her istemcinin pub / sub'larını yalnızca oturumlarında işlemesi için redis'e 2 yeni bağlantı oluşturmaya karar verdim, ardından kullanıcı bağlantıyı kestikten sonra bağlantıları kapatın. Daha sonra üretimde bir günlük kullanımdan sonra, cpu hala% 0-5 seviyesinde ... bingo! hiçbir işlem yeniden başlar, hiçbir hata, beklediğim performans ile. Şimdi node.js kayalar söyleyebilir ve bu uygulamayı oluşturmak için seçtiğim için mutluyum.

Neyse ki redis, birçok eşzamanlı bağlantıyı (mongo tarafından farklı şekilde) ele almak için tasarlanmıştır ve varsayılan olarak 10k olarak ayarlanmıştır, bu da benim için yeterli olan tek bir redis örneğinde yaklaşık 5k eşzamanlı kullanıcı için yer bırakmaktadır, ancak ben 64k eşzamanlı bağlantıya kadar itilebildiğini okudum, bu yüzden bu mimarinin yeterince sağlam olması gerektiğine inanıyorum.

Bu noktada, biraz daha optimize etmek için yeniden birleştirmek için bir çeşit bağlantı havuzları uygulamayı düşünüyordum, ancak bunların her biri olmadığı sürece pub / sub olaylarının bağlantılar üzerinde tekrar oluşmasına neden olup olmayacağından emin değilim. her seferinde onları temizlemek için yok edilir ve yeniden yaratılır.

Her neyse, cevaplarınız için teşekkürler, ne düşündüğünüzü ve başka bir öneriniz varsa merak ediyorum.

Şerefe.


2
Üretim uygulamamda da aynı sorun görünüyor gibi görünüyor, ayrıca sunucu yöneticisi rolü için yeni. Kavramda yaptıklarınızı takip ediyorum, ancak nasıl yapılacağı hakkında bazı sorularım var - belki de kabul ettiğiniz cevabınızdaki bazı kaynaklara bir bağlantı sağlayabilir misiniz? Ya da daha fazla bilgi vermek ister misiniz? Özellikle "Ama sonra her istemcinin pub / sub'larını yalnızca oturumlarında işlemesi için redis'e 2 yeni bağlantı oluşturmaya karar verdim, sonra kullanıcı bağlantıyı kestikten sonra bağlantıları kapatın."
toblerpwn

2

Dökülecek kaynak kodunuz var mı? Veritabanına bağlantılar kapatılmamış olabilir mi? Hiç kapanmayan HTTP bağlantılarını bekleyen işlemler.

Bazı günlükler gönderebilir misiniz?

Bir ps -ef yapın ve hiçbir şeyin hala çalışmadığından emin olun. Web süreçlerinin siz -9 öldürene kadar ölmeyecek zombiler bıraktığını gördüm. Bazen kapatma çalışmaz veya tam olarak çalışmaz ve bu iş parçacıkları veya işlemler RAM ve bazen CPU tutar.

Kodun herhangi bir yerinde sonsuz bir döngü veya bir db bağlantısının üstünde çökmüş bir süreç olabilir.

Hangi NPM modülleri kullanılıyor? Hepsi en yeni mi?

İstisnalar mı var? Bkz. Http://geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ Bkz: /programming/10122245/capture-node-js-crash-reason

Genel ipuçları:

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/


1

Tek başına cevap değil, çünkü sorunuz tek cevaplı bir sorudan çok bir hikaye.

Sadece 700 byte'lık bir mesaj yük kapasitesi ile 1 milyondan fazla kalıcı bağlantıyı işleyen socket.io ile bir node.js sunucusu başarıyla oluşturduğumu söylemek için.

1Gbps'de Ağ Arabirim Kartı başlangıçta doyurucu oldu ve yayınlama olaylarından tüm istemcilere çok sayıda G / Ç beklediğini görüyordum.

Proxy rolünden nginx'i kaldırmak da değerli belleği döndürdü, çünkü yalnızca ONE sunucusuyla bir milyon kalıcı bağlantıya ulaşmak, yapılandırmaları, uygulamayı ve işletim sistemi parametrelerini ayarlamak için zor bir iştir. Sadece çok fazla RAM ile yapılabileceğini unutmayın (yaklaşık 1M websockets bağlantısı yaklaşık 16GB RAM yiyor, node.js ile, sock.js'nin düşük bellek tüketimi için ideal olacağını düşünüyorum, ancak şimdilik socket.io o kadar tüketir).

Bu bağlantı , düğümlü bağlantı hacmine ulaşmak için başlangıç ​​noktamdı. Bir Erlang uygulaması olmasının yanı sıra, tüm OS ayarlamaları uygulama agnostiktir ve birçok kalıcı bağlantıyı (websockets veya uzun oylama) hedefleyen herkes tarafından kullanılmalıdır.

HTH,

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.