Node.js Http.request slows down under load testing. Am I doing something wrong?
这是我的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | var http = require('http'); var options1 = { host: 'www.google.com', port: 80, path: '/', method: 'GET' }; http.createServer(function (req, res) { var start = new Date(); var myCounter = req.query['myCounter'] || 0; var isSent = false; http.request(options1, function(response) { response.setEncoding('utf8'); response.on('data', function (chunk) { var end = new Date(); console.log(myCounter + ' BODY: ' + chunk +" time:" + (end-start) +" Request start time:" + start.getTime()); if (! isSent) { isSent = true; res.writeHead(200, {'Content-Type': 'application/xml'}); res.end(chunk); } }); }).end(); }).listen(3013); console.log('Server running at port 3013'); |
我发现的是,如果我连接到其他服务器(谷歌或任何其他服务器),响应将越来越慢,只有几秒钟。如果我连接到同一网络中的另一个node.js服务器,则不会发生。
我使用JMeter进行测试。每秒50个并发,具有1000个循环。
我不知道问题是什么...
=========================
进一步的调查:
我在Rackspace和EC2上运行相同的脚本进行测试。该脚本将使用http.request连接到:Google,Facebook,以及我的另一个脚本,该脚本仅输出由另一个EC2实例托管的数据(如hello world)。
我测试的工具只是桌面上的jMeter。
pre.node.js测试:
jMeter-> Google结果:快速且一致。
jMeter-> Facebook结果:快速且一致。
jMeter->我的简单输出脚本结果:快速且一致。
然后,我制作了50个并发线程/秒,并进行了100次循环,分别测试了我的Rackspace nodejs和EC2 node.js,后者具有同样的性能问题
jMeter-> node.js-> Google结果:在200个请求集中,从50毫秒变为2000毫秒。
jMeter-> node.js-> Facebook结果:200次重新设置后,从200毫秒变为3000毫秒。
jMeter-> node.js->我的简单输出脚本结果:200次重新设置后,从100毫秒变为1000毫秒。
前10-20个请求很快,然后开始变慢。
然后,当我更改为10个并发线程时,情况开始发生变化。响应非常一致,没有减慢的速度。
与Node.js(http.request)可以处理的并发线程数有关。
- - - - - - 更多 - - - - - - -
我今天做了更多测试,这是:
我使用了http.Agent并增加了最大套接字数。但是,有趣的是,在一台测试服务器(EC2)上,它有很多改进,并且不再降低速度。但是,其他服务器(机架空间)仅改善了一点。它仍然显示速度变慢。我什至在请求标头中设置了" Connection:close",它仅改善了100ms。
如果http.request使用连接池,如何增加连接池?
在两台服务器上,如果我执行" ulimit -a",则打开的文件数为1024。
- - - - - - - ** 越来越多 ** - - - - - - - - - -
似乎即使我将maxSockets设置为更高的数字,它也只能在某个限制下工作。似乎存在内部或操作系统相关的套接字限制。但是要撞到它吗?
------------- **经过广泛测试后** ---------------
阅读大量文章后,我发现:
引用自:https://github.com/joyent/node/issues/877
1)如果我使用connection ='keep-alive'设置标头,则性能良好,最高可以达到maxSocket = 1024(这是我的Linux设置)。
1 2 3 4 5 6 7 8 9 | var options1 = { host: 'www.google.com', port: 80, path: '/', method: 'GET', **headers: { 'Connection':'keep-alive' }** }; |
如果将其设置为" Connection":" close",响应时间将慢100倍。
有趣的事情发生在这里:
1)在EC2中,当我第一次使用Connection:keep-alive测试时,大约需要20-30毫秒。然后,如果我更改为Connection:Close或设置Agent:false,则响应时间将减慢到300毫秒。 WIHTOUT重新启动服务器,如果我再次更改为Connection:keep-alive,响应时间将进一步减慢到4000ms。我必须重新启动服务器,或者等待一段时间才能恢复20-30毫秒的照明速度响应。
2)如果我使用agent:false运行它,起初,响应时间将减慢到300ms。但是,它将再次变得更快,并恢复到"正常"状态。
我的猜测是,即使您设置了agent:false,连接池仍然有效。但是,如果您保持connection:keep-alive,那么肯定会很快。只是不要切换它。
2011年7月25日更新
我尝试通过https://github.com/mikeal/node/tree/http2上的http.js和https.js修复程序尝试最新的node.js V0.4.9
性能更好,更稳定。
我解决了
1 | require('http').globalAgent.maxSockets = 100000 |
要么
1 2 3 | agent = new http.Agent() agent.maxSockets = 1000000 # 1 million http.request({agent:agent}) |
我在同一个问题上挣扎。尽管我不清楚在哪里/为什么,但我发现瓶颈是DNS问题。如果我对http://myserver.com/asd之类的东西发出请求,我几乎无法运行50-100 rq / s,而超过100 rq / s时又有更多事情变成灾难,那么响应时间将变得巨大,有些请求永远不会完成并无限期地等待,我需要杀死-9我的服务器。如果我向服务器的IP地址发出请求,则虽然不是很平稳,但所有图形都稳定在500 rq / s,并且图形(我有实时图形)是峰值。并且请注意,Linux中打开文件的数量仍然受到限制,我设法打了一次。另一个观察结果是,单节点处理无法平稳地达到500 rq / s。但是我可以启动4个节点进程,每个进程以200 rq / s的速度运行,我得到非常平滑的图形,一致的CPU /网络负载和非常短的响应时间。这是节点0.10.22。
Github问题877可能与以下内容有关:
https://github.com/joyent/node/issues/877
尽管我不清楚这是否是您要解决的问题。当我遇到该问题时," agent:false"变通方法为我工作,对请求设置" connection:keep-alive"标头也是如此。
这不一定可以解决您的问题,但是可以稍微清理一下代码,并以应有的方式利用各种事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | var http = require('http'); var options1 = { host: 'www.google.com', port: 80, path: '/', method: 'GET' }; http.createServer(function (req, res) { var start = new Date(); var myCounter = req.query['myCounter'] || 0; http.request(options1, function(response) { res.on('drain', function () { // when output stream's buffer drained response.resume(); // continue to receive from input stream }); response.setEncoding('utf8'); res.writeHead(response.statusCode, {'Content-Type': 'application/xml'}); response.on('data', function (chunk) { if (!res.write(chunk)) { // if write failed, the stream is choking response.pause(); // tell the incoming stream to wait until output stream drained } }).on('end', function () { var end = new Date(); console.log(myCounter + ' time: ' + (end-start) +" Request start time:" + start.getTime()); res.end(); }); }).end(); }).listen(3013); console.log('Server running at port 3013'); |
我删除了身体的输出。由于我们是从一个套接字流向另一个套接字,因此我们无法确保在不缓冲的情况下随时查看整个主体。
编辑:我相信节点正在使用http.request的连接池。如果您有50个并发连接(因此有50个并发http.request尝试),则您可能会遇到连接池限制。我目前没有时间为您查找,但是您应该查看有关http的节点文档,尤其是http代理。
编辑2:关于node.js邮件列表中非常相似的问题,有一个主题。您应该看一下它,尤其是Mikael的帖子应该引起人们的兴趣。他建议通过将选项