如果有人想尝试: https://github.com/codependent/cluster-performance
我正在使用一个简单的应用程序测试Node.js(v0.11.13 - Windows 7)每秒限制请求。我已经使用Express 4实现了一个服务,该服务模拟I / O操作,例如带有setTimeout回调的数据库查询。
首先,我只用一个节点进程测试它。对于第二次测试,我启动的工作人员数量与机器的CPU数量相同。
我使用loadtest使用以下参数测试服务:
loadtest -n 50000 -c 220 -k http://localhost:5000/operations/timeout/20
也就是说,总共有50k个请求,220个并发客户端。
我的服务根据最后的url参数(20 mseg)设置超时(处理时间的持续时间):
router.route('/timeout/:time')
.get(function(req, res) {
setTimeout(function(){
appLog.debug("Timeout completed %d", process.pid);
res.json(200,{result:process.pid});
},req.param('time'));
});
结果如下:
INFO Max requests: 50000
INFO Concurrency level: 200
INFO Agent: keepalive
INFO
INFO Completed requests: 50000
INFO Total errors: 0
INFO Total time: 19.326443741 s
INFO Requests per second: 2587
INFO Total time: 19.326443741 s
INFO
INFO Percentage of the requests served within a certain time
INFO 50% 75 ms
INFO 90% 92 ms
INFO 95% 100 ms
INFO 99% 117 ms
INFO 100% 238 ms (longest request)
每秒2580个请求,不错。
在这种情况下,我使用循环调度策略在工作人员之间平均分配负载。从现在开始有8个内核处理请求,我希望每秒请求的结果有显着的改进(快8倍?)但是它只增加到2905转! (318 rps以上)你怎么解释这个?我做错了吗?
结果:
Max requests: 50000
Concurrency level: 220
Agent: keepalive
Completed requests: 50000
Total errors: 0
Total time: 17.209989764000003 s
Requests per second: 2905
Total time: 17.209989764000003 s
Percentage of the requests served within a certain time
50% 69 ms
90% 103 ms
95% 112 ms
99% 143 ms
100% 284 ms (longest request)
我的群集初始化代码:
#!/usr/bin/env node
var nconf = require('../lib/config');
var app = require('express')();
var debug = require('debug')('mma-nodevents');
var http = require("http")
var appConfigurer = require('../app');
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
if('v0.11.13'.localeCompare(process.version)>=0){
cluster.schedulingPolicy = cluster.SCHED_RR;
}
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', function(worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
cluster.fork();
});
}else{
console.log("starting worker [%d]",process.pid);
appConfigurer(app);
var server = http.createServer(app);
server.listen(nconf.get('port'), function(){
debug('Express server listening on port ' + nconf.get('port'));
});
}
module.exports = app;
更新:
我终于接受了slebetman的答案,因为他之所以正确,在这种情况下集群性能并没有因为多达8个进程而显着增加。但是我想指出一个有趣的事实:使用当前的 io.js版本(2.4.0),即使对于这种高I / O操作(setTimeout),它也确实有所改进:
loadtest -n 50000 -c 220 -k http://localhost:5000/operations/timeout/20
单线程:
Max requests: 50000
Concurrency level: 220
Agent: keepalive
Completed requests: 50000
Total errors: 0
Total time: 13.391324847 s
Requests per second: 3734
Total time: 13.391324847 s
Percentage of the requests served within a certain time
50% 57 ms
90% 67 ms
95% 74 ms
99% 118 ms
100% 230 ms (longest request)
8核心群集:
Max requests: 50000
Concurrency level: 220
Agent: keepalive
Completed requests: 50000
Total errors: 0
Total time: 8.253544166 s
Requests per second: 6058
Total time: 8.253544166 s
Percentage of the requests served within a certain time
50% 35 ms
90% 47 ms
95% 52 ms
99% 68 ms
100% 178 ms (longest request)
所以很明显,使用当前的io.js / node.js版本,虽然你没有获得8倍rps的增加,但吞吐量几乎要快1.7倍。
另一方面,正如预期的那样,使用for循环迭代请求中指示的毫秒数(从而阻塞线程),rps与线程数成比例增加。
答案 0 :(得分:18)
I / O操作正是Node.js设计和优化的应用程序类型。 I / O操作(和setTimeout)基本上与硬件(网络,磁盘,PCI桥,DMA控制器等)允许的并行运行。
一旦你意识到这一点,就很容易理解为什么在一个进程中运行许多并行I / O操作所需的时间与在许多进程/线程中运行许多并行I / O操作的时间大致相同。实际上,直接模拟将在一个进程中运行许多并行I / O操作与在许多并行进程中运行单个阻塞I / O操作完全相同。
群集允许您使用多个CPU /核心。但是您的进程不使用CPU周期。因此,聚类会给您带来很小的优势(如果有的话)。
答案 1 :(得分:0)
您是否尝试在两个或多个进程之间拆分负载测试程序?您完全有可能达到负载测试应用程序的极限。
答案 2 :(得分:0)
一个简单的计算:
1000/20*220 = 11000 // theoretically max request per second
你在localhost上测试,这意味着使用的网络时间很小,所以我猜日志输出是块
appLog.debug("Timeout completed %d", process.pid);
请评论并重试。
答案 3 :(得分:-1)
请勿使用cluster.SCHED_RR
,只需使用cluster.SCHED+