考虑以下简单的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应用程序是否可以达到那么多同时连接。
答案 0 :(得分:18)
您必须使用响应。
请记住,在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');
});
}
});
});
但是,当您不读取数据时,不会丢失数据的流的另一面是, 实际上 don&如果你没有阅读它,就会丢失数据!也就是说,他们开始暂停,你必须阅读它们才能得到任何结果。
因此,您的测试中发生的事情是您正在制作一堆请求且没有消费响应,然后最终套接字被Google杀死,因为没有正在发生,它假设你已经死了。
在某些情况下,不可能使用传入的消息:也就是说,如果您未在请求中添加response
事件处理程序,或者您在服务器上完全编写并完成response
消息而未阅读请求的地方。在这些情况下,我们只是将数据转储到垃圾箱中。
但是,如果您正在收听'response'
事件,则您有责任处理该对象。在第一个示例中添加response.resume()
,您将看到它以合理的速度处理。