2010/11/07

Node.js + Websocket Canvas共有システムが時折ダウンする問題について

2010/10/27にCanvas共有Websocketサーバーを作動させて以来、サーバーがのべ三度にわたりダウンするという問題が発生していました。原因の究明を進めていたところ、一部ダウンする状況の再現及び対処法を突き止めましたのでご報告申し上げます。なお、ダウン中にアクセスされ、Canvas共有を体験なさることが出来なかった読者の方々には深くお詫び申し上げます。これからもダウンの折には早急な原因の解明と対処に努めますので、どうか今後ともよろしくお願いいたします。

サーバーダウン時のエラー出力の内容
node.js:63
    throw e;
    ^
Error: ECONNRESET, Connection reset by peer
    at Stream._readImpl (net:304:14)
    at IOWatcher.callback (net:454:24)
    at node.js:768:9

原因
Node.jsでは発生した例外がイベントループまで到達した場合、デフォルトの動作として、スタックトレースを出力し、終了することになっています。上記の例外が発生した場合、サーバーはダウンします。なお、スタックトレースをご覧いただければわかりますとおり、例外がイベントループ内において発生していますので try/catchで捕まえることはできません。
問題は、どのような状況において上記の例外が発生するか、ということです。
上記の例外は時折にしか発生せず、原因がなにかわからなかったのですが、ようやく突き止めました。Websocketクライアントが正常に接続を終了しない場合に発生していたのです。試しにサーバーへのコネクションを張ったまま、LANケーブルを引っこ抜いてみると、まんまと上記の例外が出ました。おそらくは不安定なネットワーク環境のもとCanvas共有にアクセスし、途中でネットワークが切断された際やブラウザがクラッシュした際等に発生していたのでしょう。

対策
例外発生時の動作をデフォルトのものから変更します。
参照:Event: 'uncaughtException'

ちなみに「Connection reset by peer node.js」で検索したところ、同じ問題で困っていた仲間が大量にいました。


Node.jsで何か作る際には、あらかじめ例外発生時の動作を適切なものに設定なさることをおすすめします。デフォルトだとプロセスは終了してしまいます。
ただ、なんでもprocess.on('uncaughtException')を使って何事もなかったかのようにサーバーを動かし続けることには注意が必要な場合があります。以下を御覧ください。
node.js - Dealing with uncaught exceptions
http://debuggable.com/posts/node-js-dealing-with-uncaught-exceptions:4c933d54-1428-443c-928d-4e1ecbdd56cb

4 件のコメント:

  1. こっちでtry catchしても、上手くいかない理由の説明があると良いと思う。

    返信削除
  2. >hidekiyさん
    どのような説明があるとよいのでしょうか。具体的にご教示お願いします。

    返信削除
  3. スタックトレースでも明らかになっているけど、ECONNRESETの発生している場所が、こっちがtry catchして手におえる場所じゃないので、という感じでよろしく。

    返信削除
  4. 書き換えました。貴重なご意見ありがとうございます。英語版にも書きました。

    返信削除