web-dev-qa-db-ja.com

Socket.IO + Node.js + ZMQでメッセージを送信するときのメモリリーク

3つのアプリケーションが相互に通信しています。ブラウザからの接続を受け入れ、URLを解析して必要なデータを確認し、メモリにデータがある場合はクライアントに提供し、そうでない場合は「フェッチャー」(2)と呼ばれる別のアプリケーションから要求しないWebSocketサーバー(1)。 Fetcherはこのジョブを受信し、JSONデータを返す単純なAPI(3)から要求し、接続されたクライアントに公開するWebSockerサーバーに送り返します。次に、「Fetcher」はそのURL /ジョブに更新があるかどうかを定期的にチェックし始め、更新が発生すると新しいデータをWebSocketサーバーに送信します。

クライアントとWebSocketサーバーの通信にsocket.ioを使用しています。 Websocketサーバーとフェッチャーは[〜#〜] zmq [〜#〜]ソケットを介して通信します。

130接続でテストWebSocketサーバーをロードします。 Websocketサーバーは、毎秒160KBのデータを130のクライアントに公開します。最初は、130の接続に対して170mbのRAMを使用しますが、新しい接続はありませんが、すぐに1GBに増加します。その後、socket.ioのハートビート信号が失敗し始め、接続が切断されます。

Nodetimeを使用してヒープスナップショットを取得します。 130番目のクライアントが接続した直後のメモリの外観は次のとおりです。

enter image description here

346バッファオブジェクト、合計44MB

4分で、バッファオブジェクトの数が劇的に増加します(ここでも、新しい接続はありません)。合計メモリが486MBの3012個のオブジェクトがあります。さらに10分後、合計メモリ消費量が573MBの3535個になります。

私はMozillaのmemwatchを使用して、どの行がメモリに追加されるかを調べ、次の関数であることがわかりました。

function notifyObservers(resourceId) {
  var data = resourceData[resourceId];
  io.sockets.in(resourceId).emit('data', data);
}

これらの行をコメントアウトすると、メモリ使用量は同じままなので、別の確認です。

これがどのように起こり得るかについてのアイデアはありますか?この関数をZMQのサブスクライバーソケットメソッド内で呼び出しましたが、これと関係があると思われます。これは、関数を削除して1つにマージした場合の結果のコードです。

// Receive new resource data
const resourceUpdatedSubscriber = zmq.socket('sub').connect('tcp://localhost:5433');
resourceUpdatedSubscriber.subscribe('');

resourceUpdatedSubscriber.on('message', function (data) {
  var resource = JSON.parse(data);

  resourceData[resource.id] = resource.data;

  io.sockets.in(resourceId).emit('data', resourceData[resource.id]);
});

私のコード(負荷テストを含む)はすべて公開されており、このWebソケットサーバーは次の場所にあります: https://github.com/denizozger/node-socketio/blob/master/server.js 参照138行目。

私は2か月前にJavascriptとNode.jsの学習を始めたので、コメントを歓迎します。よろしくお願いします。

45
Deniz Ozger

NodeJはWindowsSocket API(メモリリーク、古い既知のバグを含む)を使用している可能性があります https://connect.Microsoft.com/VisualStudio/feedback/details/605621/winsock-c-program-causes-memory-leak

問題は、ネットワークサービスをシャットダウンするまでWSACleanupが呼び出されないことです。 (ZMqまたはNodejsを混同しても、その事実は変わりません)

これで、時間の経過とともに、より多くのメモリページがロックされ、最初のメモリページがいっぱいになるとそのような通知が増加します。

2
danbo

多分追加してみてください

var resourceData;

おそらくメモリリークがグローバルに関係しているため、コードのどこかに

グローバルについて詳しくは、こちらをご覧ください: https://Gist.github.com/hallettj/64478

0
Jacek Pietal