考虑以下简单的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更改为localhost,这是在我的机器上运行的极其基本的Node.js应用程序,返回“Hello world”,但我仍然遇到了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请求的最佳策略是什么?
我正在运行Mac OSX 10.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应用程序是否能够达到那么多的同时连接。
ulimit -n 2048
增加该数字,这将允许从同一 shell 运行的后续 Node 进程同时打开这些2000个与 Google 的连接,但我认为这并不是您想要的。我不确定3分钟是从哪里来的,听起来像是连接池中的限流问题(或者Google正在对您进行限流?)。 - robertklep