Node.jsのエラーECONNRESETをデバッグするにはどうすればよいですか?


288

チャットWebアプリケーションにSocket.ioを使用してExpress.jsアプリケーションを実行していますが、24時間の間に次のエラーがランダムに約5回発生します。ノードプロセスは永久にラップされ、すぐに再起動します。

問題は、Expressを再起動すると私のユーザーが部屋から追い出され、誰もそれを望まないということです。

WebサーバーはHAProxyによってプロキシされます。ソケットの安定性の問題はなく、websocketとflashsocketsトランスポートを使用するだけです。これを故意に再現することはできません。

これはNodeのエラーv0.10.11です:

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

編集(2013-07-22)

socket.ioクライアントエラーハンドラーとキャッチされない例外ハンドラーの両方を追加しました。これはエラーをキャッチしているようです:

    process.on('uncaughtException', function (err) {
      console.error(err.stack);
      console.log("Node NOT Exiting...");
    });

だから私はそれがSocket.ioの問題ではなく、私が行う別のサーバーへのHTTPリクエストか、MySQL / Redis接続ではないかと思います。問題は、エラースタックがコードの問題を特定するのに役立たないことです。これがログ出力です:

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

これの原因を知るにはどうすればよいですか?エラーからより多くのことをどのようにして得ますか?

わかりました、それほど冗長ではありませんが、ここにLongjohnのスタックトレースがあります。

    Exception caught: Error ECONNRESET
    { [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [ { receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 },
         { receiver: [Object], fun: [Function: onread], pos: 14545 },
         {},
         { receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 },
         { receiver: [Object], fun: [Function], pos: 12329 },
         { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
      __previous__:
       { [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ] } }

ここでは、フラッシュソケットポリシーファイルを提供します。

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

これが原因でしょうか?


3
@GottZ多分これは役立つかもしれません(ノードjs内で働いている誰かに話しかけます)gist.github.com/samsonradu/1b0c6feb438f5a53e30e。今日はsocket.errorハンドラーをデプロイしてお知らせします。
サムソン2013年

1
@Gottz socket.errorハンドルは役に立ちませんが、process.on( 'uncaughtException')がエラーをキャッチします。エラーのconsole.logは次のとおりです:{[Error:read ECONNRESET]コード: 'ECONNRESET'、errno: 'ECONNRESET'、syscall: 'read'}
Samson

1
ECONNRESETはネットワークの問題が原因である可能性があります。ご存知のとおり、テスト時にすべての例外をキャッチすることは不可能です。一部は本番サーバーに表示されます。サーバーを堅牢にする必要があります。Redisをストレージとして使用して、セッションの削除を処理できます。ノードサーバーがダウンした後でも、セッションが維持されます。
user568109 2013

1
なぜそれがセッションの削除に関連しているのですか?とにかく、Redisによって処理されます。
サムソン2013

3
ハンドラが設定されていないリスニングTCPポートが少なくとも1つあります。D:その1がどこにあるかをチェックするので、今の時代
モス

回答:


253

すでにご想像のとおり、接続エラーです。

「ECONNRESET」は、TCP会話の反対側が接続の終端を突然閉じたことを意味します。これは、おそらく1つ以上のアプリケーションプロトコルエラーが原因です。APIサーバーのログを見て、何か問題があるかどうかを確認できます。

しかし、エラーをチェックして問題を潜在的にデバッグする方法も探しているので、同様の質問に関連してstackoverflowに投稿されたNodeJSでソケットハングアップエラーをデバッグする方法を確認する必要があります。

開発のための迅速で汚れたソリューション

longjohnを使用する と、非同期操作を含む長いスタックトレースが取得されます。

クリーンで正しい解決策:技術的には、ノードでは'error'イベントを発行し、誰もそれをリッスンしない場合は常にスローします。スローしないようにするには、リスナーをその上に置き、自分で処理します。そうすれば、より多くの情報でエラーを記録できます。

呼び出しのグループに1つのリスナーを持たせるには、ドメイン を使用し、実行時に他のエラーをキャッチすることもできます。http(Server / Client)に関連する各非同期操作が、コードの他の部分と比較して異なるドメインコンテキストにあることを確認してください。ドメインは自動的にerrorイベントをリッスンし、独自のハンドラーに伝達します。そのため、そのハンドラのみをリッスンして、エラーデータを取得します。また、無料で詳細情報を入手できます。

編集(2013-07-22)

上で書いたように:

「ECONNRESET」は、TCP会話の反対側が接続の終端を突然閉じたことを意味します。これは、おそらく1つ以上のアプリケーションプロトコルエラーが原因です。APIサーバーのログを見て、何か問題があるかどうかを確認できます。

また、ランダムなタイミングで反対側が過負荷になり、結果として接続が強制終了されるだけです。その場合は、接続先によって異なります…

ただし、確かなことが1つあります。TCP接続で実際に読み取りエラーが発生し、例外が発生しています。編集で投稿したエラーコードを確認すると確認できます。


「突然閉鎖された」という意味ではありません。これは通常、ピアがすでに正常に閉じていた接続への書き込みが原因です。これにより、RSTが発行されます。
ローンの侯爵2014

1
@EJP私が「突然」書いたのには正当な理由がありました。エラー(警告ではない)は、接続がピアによってリセットされたことを示しています。既存の接続がリモートピアによって強制的に閉じられました。強制クローズは予期しないため突然です。(これは通常、リモートマシンのピアアプリケーションが突然停止した場合、マシンが再起動した場合、またはピアアプリケーションがリモートソケットで「強制終了」を使用した場合に発生します。このエラーは、「キープアライブ」アクティビティにより接続が切断された場合にも発生する可能性があります。 1つ以上の操作の進行中に障害を検出します...これらの操作と後続の操作は失敗します。)
e-sushi

2
テストのためにブラウザー(Chrome)から約100のAPI呼び出しをほぼ同時にバッチ送信すると、このエラーがスローされます。Chromeが過負荷になり、一部の接続を強制終了する必要があると思います... @Samson-サーバーを再起動せずに独自のドメインで各リクエストを処理し、ドメインエラーをキャッチすることの何が問題になっていますか?
スーパーシュニー2014

2
@supershneeデータ、アプリケーション、およびnode.js自体が不明な状態にあるため、キャッチされない例外が発生した後は、常にサーバーを再起動する必要があります。例外後も続行すると、データがリスクにさらされます。詳細については、プロセスに関するノードのドキュメントまたはドメインに関するノードのドキュメントをご覧ください。
c1moore 2015

39

フラッシュポリシーファイルを提供するために持っていた単純なtcpサーバーが原因でした。これで、ハンドラーを使用してエラーをキャッチできます。

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

2
コードに問題はありますか?書き込む前にソケットが書き込み可能かどうかを確認する必要がありますか?
サムソン2013

私がほとんど同じことを投稿する前に、あなたがすでに解決策を見つけたことはわかりませんでした:)しかし、あなたの質問については、ソケットが書き込み可能であることを確認しても、マイクロ秒後に書き込みを行ったときにそうではない場合がありますそれでもエラーがスローされるので、これが確実な「方法」です。
Joachim Isaksson 2013

わかりました。これが安全な方法ですか?エラーハンドラ内のsocket.close()のように?これらのエラーの後、CPU負荷が増加していると思います(不明)
Samson

2
私は常にsocket.destroy()確認するためにエラーハンドラを呼び出してきました。悲しいことに、それが必要かどうかのドキュメントを見つけることはできませんが、そうするためにエラーを出しません。
Joachim Isaksson 2013

socket.destroy()は、それが機能するものは何でも私の日を救いました!! ありがとうございました!
Firas Abd Alrahman、2016年

27

Nodeのアップグレード後にアプリでエラーが発生するという同様の問題がありました。これはノードリリースv0.9.10まで遡ることができると思います:

  • ネット:ECONNRESETを抑制しない(Ben Noordhuis)

以前のバージョンでは、クライアントからの割り込みでエラーが発生しませんでした。クライアントからの接続が切断されると、ノードにエラーECONNRESETがスローされます。これはNode向けの機能であるため、修正は(少なくとも私にとっては)エラーを処理することでした。これは、キャッチされていない例外で行われたと思います。net.socketハンドラーで処理しますが。

あなたはこれを実証することができます:

単純なソケットサーバーを作成し、ノードv0.9.9およびv0.9.10を取得します。

require('net')
    .createServer( function(socket) 
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

v0.9.9を使用して起動し、このサーバーへのFTPを試行します。Windowsを使用していて、FTPクライアントを持っているが、便利なTelnetクライアントがないという理由だけで、FTPとポート21を使用しています。

次に、クライアント側から、接続を切断します。(私はCtrl-Cを実行しています)

ノードv0.9.9を使用するとエラーは表示されず、ノードv.0.9.10以降を使用するとエラーが表示されます。

本番環境では、v.0.10を使用しています。何かとそれでもエラーが発生します。繰り返しますが、これは意図的なものであり、解決策はコード内のエラーを処理することです。


3
ありがとう、私はそれを自分で釘付けしました!アプリ全体が不安定になるため、エラーがuncaughtExceptionに伝播しないようにすることが重要です。たとえば、およそ10個のECONNRESETエラーを検出した後、サーバーが応答しなくなることがありました(フリーズして接続を処理しなかった)
Samson

エラーを抑制しなくなったノードバージョンの変更についても知っていましたが、非常に多くの問題が表示され、解決されているので、バージョンごとに最新バージョンを取得します。私は今V0.10.13を使用しています
サムソン

16

今日も同じ問題がありました。調査の結果、非常に便利な--abort-on-uncaught-exceptionnode.jsオプションが見つかりました。非常に詳細で有用なエラースタックトレースを提供するだけでなく、アプリケーションのクラッシュ時にコアファイルを保存して、さらにデバッグを行うことができます。


4
私が見ていると、この古い質問への新しい答えがポップアップするのは奇妙です-しかし、これは素晴らしいです、ありがとう
Semicolon

13

私は同じ問題に直面していましたが、以下を配置することでそれを軽減しました:

server.timeout = 0;

以前server.listenserverここはHTTPサーバーです。APIドキュメントによると、デフォルトのタイムアウトは2分です。


5
これは解決策ではなく、エラーをスローせずに物事を壊すクイックフィックスです。
Nishant Ghodke

9

サーバー間通信がありserver.maxConnections、非常に低い値に設定している場合は、もう1つの可能性があります(まれです)。

ノードのコアlib net.jsで呼び出さclientHandle.close()れ、エラーECONNRESETも発生します。

if (self.maxConnections && self._connections >= self.maxConnections) {
  clientHandle.close(); // causes ECONNRESET on the other end
  return;
}

すばらしい呼び出しですが、maxConnectionsデフォルト値はInfinityです。これは、その値を明示的にオーバーライドした場合にのみ発生します(前述のとおり)。
Gajus

7

はい、ポリシーファイルを提供すると、必ずクラッシュが発生する可能性があります。

繰り返すには、コードに遅延を追加するだけです。

net.createServer( function(socket) 
{
    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");

…そしてtelnet、ポートへの接続に使用します。遅延時間が経過する前にtelnetを切断すると、socket.writeがエラーをスローしたときにクラッシュ(キャッチされない例外)が発生します。

ここでのクラッシュを回避するには、ソケットを読み書きする前にエラーハンドラを追加します。

net.createServer(function(socket)
{
    for(i=0; i<1000000000; i++);
    socket.on('error', function() { console.log("error"); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

上記の切断を試行すると、クラッシュではなくログメッセージが表示されます。

そして、完了したら、遅延を取り除くことを忘れないでください。


6

また、私はそれを解決する方法があることで、私の開発中にECONNRESETエラーを取得していない、ちょうど使用を自分のサーバーを起動するためにnodemonを使用して"node server.js"私のサーバーは、私の問題を修正開始します。

奇妙ですが、私にとってはうまくいきました。今ではECONNRESETエラーは二度と見られません。


4

私にもこのエラーがあり、何日ものデバッグと分析の後にそれを解決することができました:

私の解決策

私にとっては、VirtualBox(Docker用)が問題でした。VMでポート転送を構成しましたが、転送されたポートでのみエラーが発生しました。

一般的な結論

以下の観察により、私が投資しなければならなかった作業の日数を節約できるかもしれません。

  • 私にとって問題は、1つのポートでのlocalhostからlocalhostへの接続でのみ発生しました。->チェックしてこれらの定数のいずれかを変更すると、問題が解決します。
  • 私にとって、問題は私のマシンでのみ発生しました->他の人に試してもらいます。
  • 私にとって問題はしばらくしてから発生し、確実に再現できませんでした
  • 私の問題は、どのノードまたはエクスプレス(デバッグ)ツールでも検査できませんでした。->これに時間を無駄にしないでください

->仮想マシン、ファイアウォールなど、ネットワークで問題が発生している(-settings)かどうかを確認します。これが問題の原因である可能性があります。


2

別のネットワークに接続するだけで問題は解決しました。これは考えられる問題の1つです。

上記で説明したように、ECONNRESETは、TCP会話が接続の終端を突然閉じたことを意味します。

インターネット接続により、一部のサーバーへの接続がブロックされている可能性があります。私の場合、mLab(MongoDBデータベースをホストするクラウドデータベースサービス)に接続しようとしていました。そして、私のISPはそれをブロックしています。


これは私にとってはうまく
いきました。

2

私はこの問題を次の方法で解決しました:

  • Wi-Fi /イーサネット接続をオフにしてからオンにします。
  • 私は入力しました:npm updatenpmを更新するためにターミナルで。
  • セッションからログアウトして再度ログインしようとした

その後、同じnpmコマンドを試しましたが、うまくいきました。それがそんなに簡単なのか確信が持てませんでした。

CENTOS 7を使用しています


0

同じ問題があり、Node.jsバージョンが問題であるようです。

以前のバージョンのNode.js(10.14.2)をインストールしましたが、nvmを使用してすべて問題ありませんでした(Node.jsのいくつかのバージョンをインストールして、バージョンをすばやく切り替えることができます)。

これは「クリーン」なソリューションではありませんが、一時的に役立ちます。


0

私は、少なくとも私のユースケースでは、これを理解しました。

私は得ていましたECONNRESET。私のクライアントの設定方法は、サーバーへのAPI呼び出しが非常に迅速に何回も行われていること、そしてエンドポイントに1回アクセスするだけで十分であることがわかりました。

修正したところ、エラーはなくなりました。


-2

これらのオプションをsocket.ioに追加してみてください:

const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };

これがお役に立てば幸いです。

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