节点js – http.request()连接池的问题

考虑以下简单的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请求。 问题是请求第5号并暂停大约3分钟,然后继续处理请求6-10,然后再暂停3分钟,然后请求11-15,暂停,等等。 编辑: 我试图改变www.google.com本地主机,一个非常基本的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请求不被locking或崩溃?

我在Mac OSX 10.8.2上运行Node.js版本0.10。


编辑:我发现如果我将上面的代码转换为for循环,并尝试build立一堆连接在同一时间,我开始得到大约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应用程序可以达到这么多的同时连接。

你必须消费回应。

请记住,在v0.10中,我们登陆了streams2。 这意味着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'); }); } }); }); 

但是,当你不读数据时,不丢失数据的数据stream的另一面是,如果你不读数据,它们实际上不会丢失数据! 也就是说,他们开始暂停,你必须阅读他们才能得到任何东西。

所以,你testing中发生的事情是你提出了一堆请求,而不是消费响应 ,然后最终套接字被谷歌杀死,因为没有任何事情发生,并假定你已经死了。

在某些情况下, 不可能使用传入的消息:也就是说,如果您没有在请求中添加response事件处理程序,或者您完全在服务器上编写并完成response消息,而没有读取请求。 在这些情况下,我们只是将数据转储到垃圾中。

但是,如果您正在聆听'response'事件,则处理该对象是您的责任。 在你的第一个例子中添加一个response.resume() ,你会看到它以合理的速度进行处理。