2011-06-01 564 views
8

这里是我的示例代码:Node.js Http.request在负载测试下变慢。难道我做错了什么?

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进行测试。 1000个循环每秒50个并发。

我不知道是什么问题...

=========================

进一步调查:

我在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 ms到200 ms后需要3000 ms。
jMeter - > node.js - >我的简单输出脚本结果:在200个请求之后,从100 ms到1000 ms。
前10-20个请求很快,然后开始放慢速度。

然后,当我更改为10个并发线程时,事情开始发生变化。响应非常一致,没有减慢。

与Node.js(http.request)可以处理的并发线程数量有关。

------------ --------------

今天我做了更多的测试,在这里,它是: 我用http.Agent并增加最大套接字。然而,有趣的是,在一台测试服务器(EC2)上,它提高了很多,并且没有更慢的速度。 HOwever,其他服务器(机架空间)只有一点改进。它仍然显示出放缓。我甚至在请求标题中设置了“Connection:close”,它只提高了100ms。

如果http.request使用连接池,如何增加它?

在这两个服务器,如果我做 “的ulimit -a”,打开文件的#1024

------------- ** 更多更多 * * -------------------

看来,即使我把maxSockets设置为更高的数字,它只能在一定的限制。似乎有一个内部或OS依赖的套接字限制。但是要碰撞它?

------------- **经过广泛的测试** ---------------

阅读大量帖子后,我发现:



转引自:https://github.com/joyent/node/issues/877


1)如果我设置的标头与连接= '保活',表现还是不错的,可以上去到maxSocket = 1024(这是我的Linux设置)。

var options1 = { 
        host: 'www.google.com', 
        port: 80, 
        path: '/', 
        method: 'GET', 
    **headers: { 
      'Connection':'keep-alive' 
    }** 
       }; 

如果我将它设置为“连接”:“关闭”,响应时间会慢100倍。

有趣的事情发生在这里:

在EC2 1),当我第一次测试与连接:保持活跃,这将需要大约20-30毫秒。然后,如果我更改为连接:关闭或设置代理:false,响应时间将减慢到300毫秒。 WIHTOUT重新启动服务器,如果我更改为Connection:再次保持活动状态,则响应时间将进一步减慢到4000毫秒。要么我必须重新启动服务器或等待一段时间才能恢复20-30ms的照明速度响应。 2)如果我使用agent运行它:false,首先,响应时间将减慢到300ms。但是,它会再次变得更快,并回到“正常”。

我的猜测是连接池仍然有效,即使你设置了agent:false。但是,如果您保持连接:保持连接,那么它肯定会很快。只是不要切换它。




7月25日更新,2011

我试图与http.js & https.js最新的node.js V0.4.9从https://github.com/mikeal/node/tree/http2

的修复性能更好更稳定。

+0

而不是做'isSent'魔法,你应该监听response.on('end')'事件。 – 2011-06-02 00:30:44

+0

感谢您的建议。 :) – murvinlai 2011-06-04 01:13:09

+0

我遇到同样的问题,并看到保持活着的变化相当大的性能增益,但是在负载测试后的一段时间我遇到了错误。 下面是错误: {[错误:连接EADDRNOTAVAIL] 代码: 'EADDRNOTAVAIL', 错误号: 'EADDRNOTAVAIL', 系统调用: '连接'} – firemonkey 2013-04-30 15:16:03

回答

1

这不会neccesarily解决您的问题,但它清理你的代码了一下,利用各种事件中,你应该的样子:

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邮件列表中的一个非常类似的问题,有a thread。你应该看看它,特别是Mikael的帖子应该是有趣的。他建议通过将选项agent: false传递给http.request调用来完全关闭连接池。我没有任何进一步的线索,所以如果这没有帮助,也许你应该尝试在node.js邮件列表上获得帮助。

+0

仍然是同样的事情。我在Rackspace服务器上运行,现在,我将尝试在EC2服务器上查看它是否有任何区别。该死的...... :( – murvinlai 2011-06-02 20:42:30

+0

请注意编辑我的答案 – 2011-06-03 06:25:56

+0

嗨,我今天做了一个测试,请在我上面的原始文章中看到我的更新:) – murvinlai 2011-06-03 08:11:36

1

Github的问题877可能涉及:

https://github.com/joyent/node/issues/877

虽然这不是我清楚,如果这是你打的是什么。当我点击“代理:虚假”解决方法时,为我工作,就像在请求中设置“连接:保持活动”标题一样。

+0

我发现的是,如果set agent:false with connection:keep-alive,速度是一致的,但有点慢。如果代理设置为连接:保持活动状态,有时候,最初的几个请求会比较慢,但它会很快。 (比代理快:false)。 如果连接没有设置,或连接:关闭,那么这将是一场灾难。 – murvinlai 2011-06-07 17:07:11

8

我解决了这个问题

require('http').globalAgent.maxSockets = 100000 

agent = new http.Agent() 
agent.maxSockets = 1000000 # 1 million 
http.request({agent:agent}) 
1

我用同样的问题所困扰。我发现我的瓶颈是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。

+1

原来这是DNS的nodejs错误。我不能肯定地说,但从我的代码检查来看,似乎有一种情况,在事件发生后可以分配“dns resolved”回调,但在发现在不稳定版本中这个方向发生了变化后,我停止深入挖掘节点的问题并没有显示在那里。似乎固定在节点0.11.9,我的无限请求问题没有在那里显示。 – bobef 2013-11-29 17:48:31