4

本番環境でフリーズしている node.js サーバーを持っています。JSONStream 内の無限ループが原因のようです。フリーズしたサーバーのコア ダンプから取得したスタック トレースを次に示します。

1: toString [buffer.js:~392] (this=0x1e28fb6d25c9 <a Buffer>#1#,encoding=0x266ee104121 <undefined>,start=0x266ee104121 <undefined>,end=0x266ee104121 <undefined>)
2: arguments adaptor frame: 0->3
3: write [/home/deploy/node_modules/JSONStream/node_modules/jsonparse/jsonparse.js:136] (this=0x32cc8dd5a999 <a Parser>#2#,buffer=0x32cc8dd5aa49 <a Buffer>#3#)
4: /* anonymous */ [/home/deploy/node_modules/JSONStream/index.js:~17] (this=0x32cc8dd5ab11 <a Stream>#4#,chunk=0x32cc8dd5aa49 <a Buffer>#3#)
5: write [/home/deploy/node_modules/JSONStream/node_modules/through/index.js:~24] (this=0x32cc8dd5ab11 <a Stream>#4#,data=0x32cc8dd5aa49 <a Buffer>#3#)
6: write [_stream_readable.js:~582] (this=0x266ee106c91 <JS Global Object>#5#,dest=0x32cc8dd5ab11 <a Stream>#4#,i=0,list=0x266ee104101 <null>)
7: flow [_stream_readable.js:592] (this=0x266ee106c91 <JS Global Object>#5#,src=0x32cc8dd5ac69 <an IncomingMessage>#6#)
8: /* anonymous */ [_stream_readable.js:560] (this=0x266ee106c91 <JS Global Object>#5#)
9: _tickCallback [node.js:415] (this=0x29e7331bb2a1 <a process>#7#)

この無限ループの原因を見つけるにはどうすればよいですか?

残念ながら、サーバーは本番環境で稼働しており、何千ものリクエストを処理しているため、追加のコンテキストを提供することは困難です. サーバーの基本的な機能は、他のサービスに対してアウトバウンド HTTP 要求を行うことです。

これがメモリリークが原因であるとは思わないことに注意してください。これらのフリーズ イベントの間、サーバーのメモリ使用量は一定 (かつ低く) に保たれますが、CPU は 99% に急上昇します。

無限ループが終了したことを示すもう 1 つの証拠は、イベント ループ自体が停止したように見えることです。setInterval 内に console.log を配置すると、サーバーがフリーズするとすぐに出力が停止します。

最大接続数を Infinity に設定することで (node.js での再利用を無効にします)、問題の原因がソケット接続の期限切れ/破損ではないことを確認しました。

JSONStream 0.7.1 を使用しています (デフォルトの jsonparse バージョン 0.0.5 が含まれています)。JSONStream リポジトリでこの問題を発見し、JSONParse をフォークして、最新の jsonparse バージョンにのみ更新しようとしました。問題は解決しませんでした。

4

1 に答える 1

3

あなたの問題はどういうわけかこの行によって引き起こされているようですjsonstream@0.0.5. サーバーを通過する内容のダンプなしで問題を最終的に修正することはできませんが、これはバッファーが非常に大きいことを示しているようです。

これは、サーバーがロックアップしている理由 (チャットで述べたように)、イベントループが進行しない理由、およびメモリが空に上がらないのに CPU が上に上がらない理由も説明します。ここでおそらく何が起こるかというtoString()と、ハードウェアでは処理できないほど大量のバイトを処理しようとして、ハードウェアが死んでしまうということです。

このリードからのさらなる調査については、必ず報告してください。開発ボックスで問題を再現することは避けられないと思います。バッファにいくつかの健全性チェックを追加し、特定のサイズを超えないようにするのと同じくらい簡単かもしれません。

コードの上記のセクションは の場合にのみヒットするn <= 128ため、符号付き文字 (Unicode など) または符号付きバイトを使用している場合、通常の関数で実際にこの問題が発生する可能性があります... 考慮すべきことかもしれません!

于 2015-10-07T15:29:41.570 に答える