Node.JS
集群clusterfork运行Node.js
使用Node.js最大的原因是因为简化,通过使用单线程范式,从而避免了多线程环境中复杂的线程编程,比如资源竞争和死锁。当然,以单线程方式运行一个Web服务器的缺点是只能利用单核CPU,而现在基本进入了多核时代,这就对资源造成了浪费,而通过Node.js的集群Cluster方式很容易更好地利用资源。
当你以集群方式运行Node.js时,将会跨多个处理器,这会更加稳定,因为在单流程情况下,当你的应用遭遇错误时,只能重新启动流程,在这段重启时间内,你的服务就中断了,集群方式可以保持一个主流程时刻了解它的子流程是否失败,会在其失败情况下自动将其请求转发到其他子流程,一直到失败的子流程重新启动。
加入集群非常容易,假设我们下面一段代码:
var express = require('express');var app = express();app.get('/', function(req, res) { res.send('Hello World!');});var server = app.listen(3000, function() { console.log('Server started on port 3000');});下面命令是是安装启动:
npm install expressnode server在浏览器打开http://localhost:3000会得到hello world。
下面是加入集群方式的代码:
var cluster = require('cluster');if (cluster.isMaster) { var numCPUs = require('os').cpus().length; for (var i = 0; i < numCPUs; i++) { cluster.fork(); }} else { var express = require('express'); var app = express(); app.get('/', function(req, res) { res.send('Hello World!'); }); var server = app.listen(3000, function() { console.log('Server started on port 3000'); });}这段代码主要增加了cluster,当应用启动后,将自己作为主流程,主流程根据CPU个数创建一个或多个子流程,一般情况下,子流程个数等于CPU的核数,主流程自己不是一个服务器,它只是负责创建和维护子流程,因为如果主流程也对外服务,一旦其失败,所有子流程都会失败。
重启
如果一个子流程失败了,主流程能够重启启动它,代码如下:
var cluster = require('cluster');if (cluster.isMaster) { var numCPUs = require('os').cpus().length; for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', function() { console.log('A worker process died, restarting...'); cluster.fork(); });} else { var express = require('express'); var app = express(); app.get('/', function(req, res) { res.send('Hello World!'); }); app.get('/explode', function(req, res) { setTimeout(function() { res.send(this.wont.go.over.well); }, 1); }); var server = app.listen(3000, function() { console.log('Server started on port 3000'); });}当你访问http://localhost:3000/explode 时,你会引起一个子流程错误,会看到控制端的堆栈跟踪,但是你的应用还是在运行,但是如果你加载explode页面多次,你会杀死所有的子流程,应用就会退出。那么有灰色背景的一段代码就能够防止在子流程退出时重新启动。
性能测试
当我们使用8核集群方式进行性能测试,单流程结果如下:
Transactions: 15932 hitsAvailability: 100.00 %Elapsed time: 19.41 secsData transferred: 0.18 MBResponse time: 0.02 secsTransaction rate: 820.64 trans/secThroughput: 0.01 MB/secConcurrency: 14.79Successful transactions: 15932Failed transactions: 0Longest transaction: 0.03Shortest transaction: 0.01而启动了集群方式的8核性能如下:
Transactions: 34479 hitsAvailability: 100.00 %Elapsed time: 19.38 secsData transferred: 0.39 MBResponse time: 0.00 secsTransaction rate: 1779.38 trans/secThroughput: 0.02 MB/secConcurrency: 7.93Successful transactions: 34489Failed transactions: 0Longest transaction: 0.07Shortest transaction: 0.00注意到第一行数据对比,有116%的性能提高。当然Node.js不是CPU-bound重CPU计算的理想选择,真实世界的结果可能与这个测试有差距,如果你有依赖CPU计算的工作,可使用Node.js作为代理,委托给其他物理机器去执行。