2013-06-02 100 views
4

在高负载服务器上进行测试,每秒处理大约500-600个请求。经过几个小时的调试,我最终只使用了一个简单的HTTP服务器。nodejs 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); 


} 
+0

我无法重现:'./wrk -c 40 http:// localhost:8085 /' - >'113603请求在10.00s,6.95GB读取,Transfer /秒:711.95MB,延迟时间3.85ms 4.81ms 53.97ms,带有64k响应。节点0.8.22和主站(v0.11.0-pre)给出的数字大致相同 –

+1

文本是静态的,还是为每个请求生成文本。 – user568109

+0

user568109 - 在原始脚本中,为每个请求生成文本,但是最后只是一个静态文本,仍然存在问题。 Andrey Sidorov - 这听起来像个好消息,我要在另一台服务器上测试它,也许它是通过某种方式连接到这台特定的机器,但我有疑问。 tnx – jsbuster

回答

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(new Buffer(str, 'binary'))替换res.end(str)。这将使用更快的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