node.js、mongodb、redis、本番環境でのubuntuのパフォーマンス低下、RAMは無料、CPU 100%


11

質問のタイトルが示すように、許容可能なパフォーマンスを達成するために、アプリケーションで何を改善できるか(またはos、ubuntuで調整できるか)を理解するのは困難です。ただし、最初にアーキテクチャについて説明します。

フロントエンドサーバーは、Ubuntu 12.04を実行する8ギガバイトのRAMを備えた8コアマシンです。アプリケーションは完全にjavascriptで記述され、node.js v 0.8.22で実行されます(一部のモジュールはノードの新しいバージョンで不満があるようです)。nginx1.4を使用して、ポート80および443から管理される8つのノードワーカーにHTTPトラフィックをプロキシしますノードクラスターAPIの使用を開始しました。socket.io 0.9.14の最新バージョンを使用して、WebSocket接続を処理します。WebSocketでは、利用可能なトランスポートとしてwebsocketとxhr-pollingのみを有効にしました。このマシンでは、Redis(2.2)のインスタンスも実行します

4ギガのRAMと2つのコアを備えたmongodb(3.6)の2番目のサーバーに永続的なデータ(ユーザーやスコアなど)を保存します。

このアプリは数か月間運用されており(数週間前まで1つのボックスで実行されていました)、1日あたり約18,000人のユーザーによって使用されています。これは、パフォーマンスの低下という主要な問題を除いて、常に非常にうまく機能しています。使用すると、各プロセスで使用されるCPUの量は、ワーカーが安定化するまで増加します(ワーカーは要求を処理しなくなります)。私は一時的に各ワーカーが使用しているCPUを1分ごとにチェックし、98%に達したら再起動します。したがって、ここでの問題は主にCPUであり、RAMではありません。socket.io 0.9.14(以前のバージョンではメモリリークが発生していました)に更新したため、RAMはもう問題ではないので、特にCPUが急速に成長するため、メモリリークの問題であるとは思えません(各ワーカーを1日に10〜12回再起動する必要があります!)。使用中のRAMも同様に大きくなり、しかし、非常にゆっくりと、使用の2〜3日ごとに1ギガ、そして奇妙なことは、アプリケーション全体を完全に再起動してもリリースされないことです。サーバーを再起動した場合にのみリリースされます!これは本当に理解できない...

私は驚くべきnodeflyを発見したので、ようやく本番サーバーで何が起こっているのかを見ることができ、数日からデータを収集しています。誰かがチャートを見たいなら、私はあなたにアクセスを与えることができますが、基本的に私は80から200の同時接続を持っていることがわかります!node.jsが数百のリクエストではなく、数千のリクエストを処理することを期待していました。また、HTTPトラフィックの平均応答時間は500〜1500ミリ秒の間で変動しますが、これは非常に大きいと思います。また、1300人のユーザーがオンラインになっているこの瞬間に、これは「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

これは、timewaitで多くの閉じられた接続を持っていることを示しています。最大オープンファイルを999999に増やしました。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

だから私は問題がいくつかの理由で利用可能なポート/ソケットを飽和させるhttpトラフィックにあると考えましたが、1つは意味がありません:なぜワーカーを再起動し、すべてのクライアントが数秒以内に再接続するのか、ワーカーのCPUの負荷は1%に低下し、約1時間後に(ピーク時に)飽和するまで要求を適切に処理できますか?

私は主にシステム管理者ではなくjavascriptプログラマーなので、サーバーでどの程度の負荷を処理する必要があるかわかりませんが、確かに期待どおりに動作していません。それ以外の場合、アプリケーションは安定しており、この最後の問題により、準備が整ったモバイルバージョンのアプリを出荷できません。明らかに、より多くの負荷がかかり、最終的にすべてがクラッシュします。

うまくいけば、私が間違っていることは明らかであり、誰かがそれを見つけるのに役立ちます...詳細についてはお気軽にお尋ねください、質問の長さは申し訳ありませんが、私は信じていました...前もって感謝します!


node.jsからスレッドダンプのようなものを取得する方法はありますか?無限ループにはおそらくいくつかのスレッドがあります。また、実際にCPUを使用しているのは何ですか?topCPU使用率が100%に近い場合、何を見ますか?
rvs

cpuはnodejsによって完全に使用されます。topを実行すると、すべてのcpuを使用するノードプロセスが表示されます。正直に言うとノードからスレッドダンプを出力する方法がわからない
...-フランジャンコ

もう1つ指摘するのは、CPU時間の大部分はユーザー時間ではなくシステムに
送ら

少なくとも、自分が設置したサーバーで処理できる同時接続数を知っている人はいますか?現時点では、最大200の同時接続をサポートしています。これは、最適な構成からどれだけ離れているかを推定するのに役立ちます...ありがとう。
フランジャンコ

回答:


10

数日間の激しい試行錯誤の後、ボトルネックがどこにあるのか理解できたと言えることを嬉しく思います。他の人が私の発見から利益を得ることができるように、ここに投稿します。

この問題は、socket.ioで使用していたpub / sub接続、特にsocket.ioがソケットインスタンスのプロセス間通信を処理するために使用するRedisStoreにあります。

redisを使用して自分のバージョンのpub / subを簡単に実装できることに気付いた後、試してみると、socket.ioからredisStoreを削除し、デフォルトのメモリストアのままにしておきます(ブロードキャストする必要はありません)接続されているすべてのクライアント、ただし異なるプロセスに接続している可能性のある2人の異なるユーザー間のみ)

最初は、接続されたすべてのクライアントでpub / subを処理するための2つのグローバルなredis接続xプロセスのみを宣言しました。しかし、その後、各クライアントのredisへの2つの新しい接続を作成して、セッションでのみpub / subを処理し、ユーザーが切断したら接続を閉じることにしました。その後、実稼働環境で1日使用した後、CPUは0〜5%のままでした...ビンゴ!プロセスの再起動やバグはなく、期待通りのパフォーマンスが得られました。これで、node.jsが素晴らしいと言えます。このアプリを構築するためにnode.jsを選択できたことを嬉しく思います。

幸いなことに、redisは多くの同時接続を処理するように設計されており(mongoによって異なります)、デフォルトでは10kに設定されており、1つのredisインスタンスで約5,000人の同時ユーザー用のスペースを残しています。最大64kの同時接続までプッシュできることを読んだため、このアーキテクチャは十分に堅固であると信じています。

この時点で、redisに何らかの接続プールを実装して、それをもう少し最適化することを考えていましたが、それがそれぞれの接続を除き、pub / subイベントが再び接続に蓄積しないかどうかはわかりませんそれらをきれいにするために、毎回破壊され、再作成されます。

とにかく、あなたの答えをありがとう、そして私はあなたがどう思うか、そして他に何か提案があれば知りたいです。

乾杯。


2
本番アプリでも同じ問題と思われるものがありますが、これもサーバー管理者の役割に新しいものです。私はあなたがコンセプトでしたことに従いますが、それを行う方法についていくつか質問があります-おそらくあなたはあなたの受け入れられた答えでいくつかのリソースへのリンクを提供できますか?または、単により多くの情報を提供しますか?特に「しかし、セッションでのみpub / subを処理するために各クライアントのredisへの2つの新しい接続を作成し、ユーザーが切断したら接続を閉じることにしました。」
-toblerpwn

2

ダンプするソースコードはありますか?データベースへの接続が閉じられていない可能性がありますか?決して閉じないHTTP接続を待機しているプロセス。

ログを投稿できますか?

ps -efを実行し、まだ何も実行されていないことを確認します。あなたがkill -9をするまで死ぬことのないゾンビを残すウェブプロセスを見てきました。シャットダウンが機能しない場合や完全に機能しない場合があり、これらのスレッドまたはプロセスはRAMを保持し、CPUを保持することもあります。

コードのどこかに無限ループがあるか、db接続の上に保持されているプロセスがクラッシュしている可能性があります。

どのNPMモジュールが使用していますか?それらはすべて最新ですか?

例外をキャッチしていますか?参照:http : //geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ 参照:https : //stackoverflow.com/questions/10122245/capture-node-js-crash-reason

一般的なヒント:

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

あなたの質問は一問一答の質問というよりも物語なので、それ自体は答えではありません。

socket.ioを使用してnode.jsサーバーを正常に構築し、メッセージペイロードの平均が700バイトの100万を超える永続的な接続を処理したことを伝えます。

最初は1Gbpsのネットワークインターフェイスカードが飽和状態でしたが、発行イベントからすべてのクライアントへのI / Oの待機が大量に発生していました。

プロキシロールからnginxを削除しても貴重なメモリが返されました。1台のサーバーだけで100万の永続的な接続に到達することは、構成、アプリケーションの調整、OSパラメーターの調整が難しいためです。大量のRAMでのみ実行可能であることに留意してください(約1MのWebソケット接続は約16GBのRAMを消費し、node.jsでは、sock.jsを使用することが低メモリ消費に理想的だと思いますが、現時点ではsocket.ioそのくらい消費します)。

このリンクは、ノードとの接続のボリュームに到達するための出発点でした。Erlangアプリであることに加えて、すべてのOSチューニングはほとんどアプリケーションに依存しないため、多くの永続的な接続(Webソケットまたはロングポーリング)を目的とするすべてのユーザーが使用する必要があります。

HTH、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.