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

mur*_*lai 9 http request load-testing node.js

这是我的示例代码:

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');
Run Code Online (Sandbox Code Playgroud)

我发现,如果我连接到其他服务器(谷歌或任何其他),响应将变得越来越慢,几秒钟.如果我连接到同一网络中的另一个node.js服务器,则不会发生这种情况.

我用JMeter来测试.每秒50个并发,1000个循环.

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

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

进一步的调查:

我在Rackspace上运行相同的脚本,也在EC2上运行以进行测试.该脚本将使用http.request连接到:Google,Facebook,以及我的另一个脚本,它只是输出由另一个EC2实例托管的数据(如hello world).

测试工具我就是桌面上的jMeter.

pre-node.js test:jMeter - > Google Result:快速且一致.jMeter - > Facebook结果:快速且一致.jMeter - >我的简单输出脚本结果:快速且一致.

然后我用100个循环制作50个Concurrent Threads/sec,测试我的Rackspace nodejs,然后测试具有相同性能问题王的EC2 node.js jMeter - > node.js - > Google Result:从50 ms开始在200个重新设定中2000毫秒.
jMeter - > node.js - > Facebook结果:200个重新设置后,从200毫秒到3000毫秒.
jMeter - > node.js - >我的简单输出脚本结果:从100 ms开始,在200次重新设置之后转换为1000 ms.
前10-20个请求很快,然后开始减速.

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

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

------------ 更多 --------------

我今天做了更多测试,这里是:我使用了http.Agent并增加了最大套接字.然而,有趣的是,在一个测试服务器(EC2)上,它改进了很多而且没有更慢.HOwever,另一台服务器(rackspace)只有一点点改进.它仍显示减速.我甚至在请求标题中设置了"Connection:close",它只提高了100ms.

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

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

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

似乎即使我将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'
    }**
                };
Run Code Online (Sandbox Code Playgroud)

如果我将其设置为"连接":"关闭",则响应时间将慢100倍.

有趣的事发生在这里:

1)在EC2中,当我第一次使用Connection进行测试时:保持活动状态,大约需要20-30 ms.然后,如果我更改为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以及来自https://github.com/mikeal/node/tree/http2的http.js和https.js修复程序

性能更好,更稳定.

hai*_*jin 8

我解决了这个问题

require('http').globalAgent.maxSockets = 100000
Run Code Online (Sandbox Code Playgroud)

要么

agent = new http.Agent()
agent.maxSockets = 1000000  # 1 million
http.request({agent:agent})
Run Code Online (Sandbox Code Playgroud)


Dan*_*lig 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');
Run Code Online (Sandbox Code Playgroud)

我去掉了身体的输出。由于我们从一个套接字流式传输到另一个套接字,因此我们无法确保在不缓冲的情况下随时看到整个主体。

编辑:我相信节点正在使用连接池进行http.request。如果您有 50 个并发连接(因此有 50 个并发 http.request 尝试),您可能会遇到连接池限制。我目前没有时间为您查找此内容,但您应该查看有关 http 的节点文档,尤其是 http 代理。

编辑 2: node.js 邮件列表上有一个关于非常相似问题的线程。你应该看看它,尤其是 Mikael 的帖子应该很有趣。agent: false他建议通过将该选项传递给调用来完全关闭请求的连接池http.request。我没有任何进一步的线索,所以如果这没有帮助,也许您应该尝试在 node.js 邮件列表上获取帮助。