nodejs HTTP服务器无法在高负载下处理大响应

时间:2013-06-02 23:33:06

标签: node.js

在高负载服务器上测试,每秒大约有500-600个请求。 经过几个小时的调试,我最终得到了一个简单的HTTP服务器。

我注意到当响应体变大时,让我们说,60k,我收到了这个错误:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at Socket.EventEmitter.addListener (events.js:160:15)
    at Socket.Readable.on (_stream_readable.js:679:33)
    at Socket.EventEmitter.once (events.js:179:8)
    at TCP.onread (net.js:527:26)

之后CPU变得疯狂

但是,使用完全相同的代码,当响应设置为10k的文本时,一切都顺利进行。 奇怪的...

有没有人遇到过这个??? 请求帮助。

这是完整的脚本:

var
cluster = require('cluster'),
numCPUs = require('os').cpus().length;



if(cluster.isMaster){

    for (var i = 0; i < numCPUs; i++) cluster.fork();

    cluster.on("exit", function(worker, code, signal) {
        cluster.fork();
    });

}
else{


    var http = require('http');


    var app = function(req, res){

        res.writeHead(200, {'Content-Type': 'text/html', 'Access-Control-Allow-Origin': '*'});
        res.end( 60k_of_text___or___10k_of_text );

    };


    http.createServer(app).listen(80);


}

1 个答案:

答案 0 :(得分:0)

现在所有字符串首先转换为Buffer实例。这可能会在每次请求后对垃圾收集器进行大量加载以进行清理。使用--prof运行您的应用并使用v8.log检查tools/*-tick-processor文件,您可能会看到。

正在努力纠正这一问题,因此字符串会直接写入内存,然后在请求完成时进行清理。它已经在f5e13ae中用于文件系统写入,但还没有用于其他情况(实现起来比听起来要困难得多)。

将字符串转换为缓冲区也非常昂贵。特别是对于utf8字符串(默认值)。你可以在哪里,绝对预先将字符串缓存为缓冲区并使用它。这是一个示例脚本:

var http = require('http');
var str = 'a';
for (var i = 0; i < 60000; i++)
  str += 'a';

//str = new Buffer(str, 'binary');

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain',
                      'Access-Control-Allow-Origin': '*'});
  res.end(str);
}).listen(8011, '127.0.0.1');

以下是针对服务器运行wrk 'http://127.0.0.1:8011/'首先将str作为字符串传递,然后作为持久缓冲区的结果:

Running 10s test @ http://127.0.0.1:8011/
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec     0.00      0.00     0.00      -nan%
  8625 requests in 10.00s, 495.01MB read
Requests/sec:    862.44
Transfer/sec:     49.50MB


Running 10s test @ http://127.0.0.1:8011/
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   624.07us  100.77us   4.45ms   99.17%
    Req/Sec     7.98k   729.82     9.00k    57.59%
  158711 requests in 10.00s, 8.90GB read
Requests/sec:  15871.44
Transfer/sec:      0.89GB

至少如果你知道你的传递只包含ascii字符的字符串,那么用res.end(str)替换res.end(new Buffer(str, 'binary'))。这将使用更快的v8::String::WriteOneByte方法。以下是使用该更改的结果:

Running 10s test @ http://127.0.0.1:8011/
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   827.55us  540.57us   7.03ms   97.38%
    Req/Sec     6.06k     1.11k    8.00k    85.93%
  121425 requests in 10.00s, 6.81GB read
Requests/sec:  12142.62
Transfer/sec:    696.89MB