Node.js集群并没有显着提高性能

时间:2014-11-06 14:02:34

标签: javascript node.js cluster-computing

如果有人想尝试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'));
});    
  1. 只有一个节点流程
  2. 结果如下:

    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个请求,不错。

    1. n名工人(n = numCPUs)
    2. 在这种情况下,我使用循环调度策略在工作人员之间平均分配负载。从现在开始有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与线程数成比例增加。

4 个答案:

答案 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+