10

次の単純なNode.jsアプリケーションについて考えてみます。

var http = require('http');
http.createServer(function() { }).listen(8124); // Prevent process shutting down

var requestNo = 1;
var maxRequests = 2000;

function requestTest() {
    http.request({ host: 'www.google.com', method: 'GET' }, function(res) {
        console.log('Completed ' + (requestNo++));

        if (requestNo <= maxRequests) {
            requestTest();
        }
    }).end();
}

requestTest();

google.comに対して2000件のHTTPリクエストを次々に作成します。問題は、No。5をリクエストし、約3分間一時停止してから、リクエスト6〜10の処理を続行し、さらに3分間一時停止してから、リクエスト11〜15、一時停止などです。編集: www.google.comをlocalhostに変更しようとしました。これは、「Hello world」を返す、マシンを実行している非常に基本的なNode.jsアプリですが、それでも3分間休止します。

今、私は接続プールの制限を増やすことができると読みました:

http.globalAgent.maxSockets = 20;

これを実行すると、リクエスト1〜20を処理してから、3分間一時停止し、次にリクエスト21〜40を処理してから、一時停止します。

最後に、少し調べてみagent: falseたところ、リクエストオプションを設定することで、接続プールを完全に無効にできることがわかりました。

http.request({ host: 'www.google.com', method: 'GET', agent: false }, function(res) {
    ...snip....

...そして、2000のすべてのリクエストを問題なく実行します。

私の質問ですが、これを行うのは良い考えですか?HTTP接続が多すぎるという危険性はありますか?そして、なぜそれは3分間一時停止するのですか?接続が終了した場合は、次の要求を使用できるようにプールに直接追加する必要があります。なぜ3分間待機するのでしょうか。私の無知を許してください。

それができない場合、Node.jsアプリが、ロックしたりクラッシュしたりすることなく、潜在的に多数のHTTPリクエストを作成するための最良の戦略は何ですか?

MacOSX10.8.2でNode.jsバージョン0.10を実行しています。


編集:上記のコードをforループに変換し、同時に多数の接続を確立しようとすると、約242の接続後にエラーが発生し始めます。エラーは次のとおりです。

Error was thrown: connect EMFILE
(libuv) Failed to create kqueue (24)

...そしてコード...

for (var i = 1; i <= 2000; i++) {
    (function(requestNo) {
        var request = http.request({ host: 'www.google.com', method: 'GET', agent: false }, function(res) {
            console.log('Completed ' + requestNo);
        });

        request.on('error', function(e) {
            console.log(e.name + ' was thrown: ' + e.message);
        });

        request.end();
    })(i);
}

負荷の高いNode.jsアプリが、これほど多くの同時接続に到達できるかどうかはわかりません。

4

1 に答える 1

19

応答を消費する必要があります。

v0.10 では、stream2 を導入したことを思い出してください。つまり、data探し始めるまでイベントは発生しません。したがって、次のようなことができます。

http.createServer(function(req, res) {
  // this does some I/O, async
  // in 0.8, you'd lose data chunks, or even the 'end' event!
  lookUpSessionInDb(req, function(er, session) {
    if (er) {
      res.statusCode = 500;
      res.end("oopsie");
    } else {
      // no data lost
      req.on('data', handleUpload);
      // end event didn't fire while we were looking it up
      req.on('end', function() {
        res.end('ok, got your stuff');
      });
    }
  });
});

ただし、読み取っていないときにデータを失わないストリームの裏側は、読み取っていなくても実際にはデータを失わないということです! つまり、それらは一時停止して開始され、何かを得るにはそれらを読む必要があります。

したがって、テストで起こっていることは、一連のリクエストを作成し、応答を消費していないということです。その後、何も起こっていないため、最終的にソケットがGoogleによって強制終了され、死亡したと見なされます。

着信メッセージを消費できない場合があります。つまり、リクエストにイベント ハンドラを追加しない場合や、リクエストを読み取らずにサーバー上でメッセージresponseを完全に書き込んで終了する場合です。responseそのような場合、私たちはあなたのためにデータをゴミに捨てます。

ただし、イベントをリッスンしている場合は'response'、オブジェクトを処理する責任があります。最初の例に a を追加するresponse.resume()と、妥当なペースで処理が進むことがわかります。

于 2013-03-21T00:46:19.090 に答える