51

この問題により、本番サーバーの安定性が損なわれています。

要約すると、基本的な考え方は、ノード サーバーが断続的に遅くなり、ゲートウェイ タイムアウトが発生することがあるということです。私のログからわかる限り、何かがノード スレッドをブロックしています (つまり、着信要求が受け入れられないことを意味します) が、何が原因であるかを突き止めることはできません。

問題の重大度はさまざまです。100 ミリ秒未満のリクエストが完了するまでに最大 10 秒かかる場合があります。ノードサーバーにまったく受け入れられないこともあります。要するに、ランダムなタスクが動作し、一定期間ノード スレッドをブロックしているように見えます。確かに言えることは、修正が必要な症状は「ゲートウェイタイムアウト」であるということです。

この問題は予告なしに行き来します。CPU 使用率、RAM 使用率、稼働時間、またはその他の関連する統計と関連付けることができませんでした。サーバーが大きな負荷を正常に処理し、小さな負荷でこのエラーが発生するのを見たので、負荷に関連しているようには見えません. 1 日の最小ロード時間である PST の午前 1 時頃にエラーが表示されることは珍しくありません。ノードアプリを再起動すると、問題がしばらく解消されるようですが、実際にはあまりわかりません. それはnode.jsのバグではないかと思います...本番サーバーが停止していることを考えると、あまり安心できません。

  • 私が最初にしたことは、node.js を最新 (0.8.12) にアップグレードしたことと、すべてのモジュール (ここにある) を確認することでした。もちろん、エラーキャッチャーもたくさん用意しています。コンソールに大量に出力したり、大量のファイルに書き込んだりするようなおかしなことはしていません。
  • Expressミドルウェアがインバウンドリクエストを拾っていないので、最初はアウトバウンドHTTPリクエストがインバウンドソケットをブロックしていると思っていましたが、ノードスレッド自体がビジーになったように見えるため、理論を断念しました。
  • 次に、JSHint を使用してすべてのコードを調べ、いくつかの偶発的なグローバル (「var」を書き忘れた) を含め、文字通りすべての警告を修正しましたが、これは役に立ちませんでした。
  • その後、おそらくメモリが不足していると思いました。しかし、nodetime を介したヒープ スナップショットは、かなり良好に見えます (以下で説明します)。
  • まだメモリが問題かもしれないと考えて、ガベージコレクションを調べました。--nouse-idle-notification フラグを有効にし、必要のない NULL オブジェクトに対してさらにコードの最適化を行いました。
  • 問題はメモリにあると確信していたので、 --expose-gc フラグを追加して gc(); を実行しました。毎分コマンド。これは、おそらくリクエストを少し遅くすることを除いて、何も変更しませんでした.
  • 必死の試みで、2 つのワーカーを使用して 30 分ごとに自動的に再起動するように「クラスター」モジュールをセットアップしました。それでも、運が悪い。
  • ulimit を 10,000 以上に増やし、開いているファイルを監視しました。node.js アプリごとに 300 個未満の開いているファイル (またはソケット) があるようで、ulimit を増やしても影響はありませんでした。

私は自分のサーバーをノードタイムでログに記録してきましたが、その要旨は次のとおりです。

  • Amazon クラウドで実行されている CentOS 5.2 (m1.large インスタンス)
  • 常に 5000 MB を超える空きメモリ
  • 常に 150 MB 未満のヒープ サイズ
  • CPU 使用率は常に 60% 未満です

また、CPU 使用率が 5% 未満で、完了までに 100 ミリ秒を超えるリクエストがない MongoDB サーバーも確認したので、ボトルネックがあるとは思えません。

Q-promise を使用して (ほぼ) すべてのコードをラップし (コード サンプル を参照)、もちろん疫病のような Sync() 呼び出しを回避しました。テスト サーバー (OSX) で問題を再現しようとしましたが、うまくいきませんでした。もちろん、これは、運用サーバーが非常に多くの人々によって予測不可能な方法で使用されているためであり、ストレス テストで再現することはできません...

4

7 に答える 7

15

最初にこの質問をしてから数か月後、答えを見つけました。

一言で言えば、問題は、あるサーバーから別のサーバーに転送するときに大きな資産をパイプしていなかったことです。つまり、S3 バケットにアップロードする前に、1 つのサーバーから画像をダウンロードしていました。ダウンロードをアップロードにストリーミングする代わりに、ファイルをメモリにダウンロードしてからアップロードしました。

これがメモリ スパイクとして表示されなかった理由、または統計の他の場所に表示されなかった理由はわかりません。

于 2013-03-28T22:06:08.600 に答える
12

私の推しはマングースです。Mongo に大きなペイロードを格納している場合、Mongoose オブジェクトの構築方法が原因で、Mongoose はかなり遅くなる可能性があります。問題の詳細については、https://github.com/LearnBoost/mongoose/issues/950を参照してください。これが問題である場合、クエリがすぐに返されるため、Mongo 自体には表示されませんが、オブジェクトのインスタンス化には 75 倍のクエリ時間がかかる可能性があります。

process.hrtime()Mongoose オブジェクトが作成される前後に ( ) の前後にタイマーを設定してみて、それが問題であるかどうかを確認してください。これが問題である場合は、Mongoose を経由する代わりに、ノード Mongo ドライバーを直接使用することに切り替えます。

于 2012-10-17T20:02:45.323 に答える
4

大量のメモリ リークが発生しています。必要がなくなったらすぐに、すべてのオブジェクトを null に設定してみてください。これを読んでください

メモリ リークの追跡に関する詳細については、こちらを参照してください。

同じオブジェクトへの複数の参照があることに特に注意し、循環参照があるかどうかを確認してください。これらはデバッグが面倒ですが、非常に役立ちます。

ガベージ コレクターを 1 分ごとに手動で呼び出してみてください (私は C++ と PHP のコーダーなので、node.js でこれを実行できるかどうかはわかりません)。私の長年の C++ の使用経験から、時間の経過とともにアプリケーションが遅くなる原因として最も可能性が高いのはメモリ リークであることがわかります。それらを見つけて接続すれば、問題はありません。

また、メモリ内の画像、オーディオ、ビデオ、またはそのようなものをキャッシュおよび/または処理していないと仮定すると、150Mヒープはたくさんあります! それらは数十万、あるいは数百万の小さなオブジェクトである可能性があります。

アプリケーションが遅くなるためにメモリが不足している必要はありません...すでに割り当てられている多くのオブジェクトで空きメモリを検索することは、メモリアロケータにとって大きな仕事であり、新しいオブジェクトをそれぞれ割り当てるには多くの時間がかかりますオブジェクトであり、メモリリークが増えるにつれて、その時間は増加するだけです。

于 2012-10-14T22:48:49.367 に答える
1

私がすることは、ある種のエコーサービスを使用して同じサーバー上に並列ノードインスタンスをセットアップし、それをテストすることです。正常に動作する場合は、問題をプログラムコードに絞り込みます(スケジューラ/ OSレベルの問題ではありません)。次に、段階的にモジュールを含めて、もう一度テストします。確かに、これは多くの作業であり、時間がかかり、システムで実行可能かどうかはわかりません。

于 2012-10-19T07:30:45.557 に答える
1

これを今すぐ機能させる必要がある場合は、NASAの冗長ルートを使用できます。

本番サーバーの2番目のコピーを作成し、それらの前にプロキシを配置して、各要求を両方のスタックにルーティングし、最初の応答を返します。これを完全な長期ソリューションとしてはお勧めしませんが、本番環境での問題を大幅に減らし、非本番サーバーで問題を再現するために再生できるログデータを収集するのに役立つはずです。

明らかに、これは読み取り要求の場合は簡単ですが、データベースに書き込むコマンドの場合はより複雑です。

于 2012-10-24T00:43:07.937 に答える
1

「--nouse-idle-connection」は間違いですか? 本当に「--nouse_idle_notification」のことですか?

小さなオブジェクトが多すぎるgcに関する問題だと思います。ノードは単一のプロセスであるため、負荷よりも最もビジーな CPU コアを監視することが重要です。プログラムが遅い場合は、「gdb node pid」と「bt」を実行して、どのノードがビジーであるかを確認できます。

于 2012-10-18T02:13:50.060 に答える
0

Node.js サーバーにも同様の問題があります。それは何週間もうまくスケーリングできず、私たちはあなたと同じようにほとんどすべてを試しました. 私たちの問題は、並行性の高い環境では非常に低く設定されている暗黙のバックログ値にありました。

http://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback

バックログを大幅に高い値 (例: 10000) に設定し、マニュアルのセクションで説明されているように、カーネル (Linux では /etc/sysctl.conf) のネットワークを調整すると、多くの助けになりました。この時点から、Node.js サーバーにタイムアウトはありません。

于 2012-10-27T11:27:35.123 に答える