Node.js Http.request在负载测试下变慢。难道我做错了什么?

时间:2011-06-01 23:55:35

标签: http node.js request load-testing

以下是我的示例代码:

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 - >我的简单输出脚本结果:快速且一致。

然后我用100个循环制作50个Concurrent Threads / sec,测试我的Rackspace nodejs,然后测试具有相同性能问题王的EC2 node.js   jMeter - > node.js - >谷歌搜索结果:在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)上,它改进了很多而且没有更慢。 HOwever,另一台服务器(rackspace)只有一点点改进。它仍显示减速。我甚至在请求标题中设置了“Connection:close”,它只提高了100ms。

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

在两个服务器中,如果我执行“ulimit -a”,则打开的文件数为1024.

------------- ** MORE AND MORE ** ------------------- < / p>

似乎即使我将maxSockets设置为更高的数字,它只能在某个限制下工作。似乎存在内部或OS依赖的套接字限制。然而要提高它?

------------- **广泛测试后** ---------------

在阅读了很多帖子后,我发现:



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


1)如果我使用connection ='keep-alive'设置标头,性能很好,可以达到maxSocket = 1024(这是我的linux设置)。

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

如果我将其设置为“Connection”:“close”,则响应时间将慢100倍。

有趣的事情发生在这里:

1)在EC2中,当我第一次使用Connection进行测试时:保持活动状态,大约需要20-30毫秒。然后,如果我更改为Connection:Close或设置Agent:false,响应时间将减慢到300 ms。 WIHTOUT重新启动服务器,如果我再次切换到Connection:keep-alive,响应时间将进一步减慢到4000ms。要么我必须重新启动服务器,要么等待一段时间才能恢复20-30ms的照明速度响应。

2)如果我使用agent运行它:false,首先,响应时间将减慢到300ms。但是,它会再次变得更快并恢复到“正常”状态。

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




2011年7月25日更新

我尝试了最新的node.js V0.4.9和http.js&amp; https.js修复自https://github.com/mikeal/node/tree/http2

性能更好,更稳定。

4 个答案:

答案 0 :(得分:8)

我用

解决了这个问题
require('http').globalAgent.maxSockets = 100000

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

答案 1 :(得分:3)

我正在努力解决同样的问题。我发现我的瓶颈是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。

答案 2 :(得分:1)

这不一定会解决您的问题,但它会稍微清理您的代码并以您应该的方式利用各种事件:

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邮件列表上获得帮助。

答案 3 :(得分:1)

Github问题877可能是相关的:

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

虽然我不清楚这是不是你要打的。当我点击时,“agent:false”解决方法对我起作用,就像在请求中设置“connection:keep-alive”标题一样。