解读node.js的cluster模块

       在现在机器的CPU都是多核的背景下,Node的单线程设计已经无法更充分的"压榨"机器性能了。因此从v0.8开始,Node新增了一个内置模块——“cluster”,故名思议,它能够经过一个父进程管理一坨子进程的方式来实现集群的功能javascript

快速上手

使用十分的简单,以下java

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length; // 获取CPU的个数
 
if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
 
    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}

        稍微解释下,经过isMaster属性,判断是否Master进程,是则fork子进程,不然启动一个server。每一个HTTP server都能监听到同一个端口。node

        可是在实际项目中,咱们的启动代码通常都已经封装在了app.js中,要把整块启动逻辑嵌在上面的if else中实在不优雅。 因此,咱们能够这样:nginx

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
 
if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
    // 其它代码
    
} else {
    require("./app.js");
}

        简单之处就在于本来的应用逻辑根本不须要知道本身是在集群仍是单边。(固然,若是应用在内存中维护了某些状态,好比session,就须要运用某些机制来共享了,这里不详说)git

经常使用API

        cluster模块提供了一大坨事件和方法,这里挑一些经常使用的说明下,详细的请参考官方文档。github

cluster.setupMaster([settings])

       setupMaster用来改变默认设置,只能被调用一次,调用后,配置会存在且冻结在cluster.settings里。配置只会影响fork时的行为,实际上这些选项就是传给fork用的,有兴趣的同窗能够去对照child_process.fork()的参数。算法

       具体有以下选项:windows

  • execArgv Node执行时的变量数组,传递给node(默认为process.execArgv)。
  • exec 执行的文件,配置后就不须要像最开始的例子,在代码里require目标文件了(默认为process.argv[1])。
  • args 传递给worker的变量数组(默认为process.argv.slice(2)))。
  • silent 是否禁止打印内容(默认为false)。
  • uid 设置进程的用户ID。
  • gid 设置进程的组ID。

Event: fork和online

       当一个新的worker被fork时就会触发fork事件,而在worker启动时才会触发online事件,因此fork先触发,online后触发。能够在这两个事件的callback里作些初始化的逻辑,也能够在这时向master报告:“我起来了!”。数组

Event: exit

       当任何一个worker停掉都会触发exit事件,能够在回调里增长fork动做重启。session

       经过worker.suicide来判断,worker是意外中断仍是主动中止的(在worker中调用kill和disconnect方法,视做suide。)。

cluster.on('exit', function(worker, code, signal) {
    console.log('worker %d died (%s). restarting...',
        worker.process.pid, signal || code);
    cluster.fork();
});

cluster.worker和cluster.workers

       前者是一份worker对象的引用,只能在worker里使用。后者是master下对当前可用worker的一个Object,key为worker id,注意,当worker已经exit或disconnect后就不会在这个object里了。

Event: message

       message事件能够用来作master和worker的通讯机制。

       利用这套机制,能够用来实现不间断重启

       文章最开始的例子有个问题,尤为是运行在生产环境还不够健壮:若是某个worker由于意外“宕机”了,代码并无任何处理,这时若是咱们重启应用又会形成服务中断。利用这些API就能够利用事件监听的方式作相应处理。

原理

       每一个worker进程经过使用child_process.fork()函数,基于IPC(Inter-Process Communication,进程间通讯),实现与master进程间通讯。

       什么是fork,Linux API给了以下解释

fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.

The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings (munmap(2)) performed by one of the processes do not affect the other.

       咱们能够看到,fork出的子进程拥有和父进程一致的数据空间、堆、栈等资源(fork当时),可是是独立的,也就是说两者不能共享这些存储空间。 那咱们直接用fork本身实现不就好了,干吗须要cluster呢。

        “这样的方式仅仅实现了多进程。多进程运行还涉及父子进程通讯,子进程管理,以及负载均衡等问题,这些特性cluster帮你实现了。”

       这里再说下cluster的负载均衡。Node.js v0.11.2+的cluster模块使用了round-robin调度算法作负载均衡,新链接由主进程接受,而后由它选择一个可用的worker把链接交出去,说白了就是轮转法。算法很简单,但据官方说法,实测很高效。

       注意:在windows平台,默认使用的是IOCP,官方文档说一旦解决了分发handle对象的性能问题,就会改成RR算法(没有时间表。。)

       若是想用操做系统指定的算法,能够在fork新worker以前或者setupMaster()以前指定以下代码:

cluster.schedulingPolicy = cluster.SCHED_NONE;

       或者经过环境变量的方式改变

$ export NODE_CLUSTER_SCHED_POLICY="none" # "rr" is round-robin
$ node app.js

       或在启动Node时指定

$ env NODE_CLUSTER_SCHED_POLICY="none" node app.js

使用pm2实现cluster

       pm2是一个现网进程管理的工具,能够作到不间断重启、负载均衡、集群管理等,比forever更强大。利用pm2能够作到no code but just config实现应用的cluster。

      安装pm2什么的这里就不赘述了。用pm2启动时,经过-i指定worker的数量便可。若是worker挂了,pm2会自动马上重启,各类简单省心。

$ pm2 start app.js -i 4

      也能够在应用运行时,改变worker的数量,以下图


     更多的使用方法,能够去github上慢慢看(说句题外话,若是有相似PM2,甚至更好的PM工具,欢迎在评论里回复^_^)。

多机器集群

      cluster适用于在单台机器上,若是应用的流量巨大,多机器是必然的。这时,反向代理就派上用场了,咱们能够用node来写反向代理的服务(好比用http-proxy),好处是能够保持工程师技术栈的统一,不过生产环境,咱们用的更多的仍是nginx,这里就很少介绍了。

转载自AlloyTeam:http://www.alloyteam.com/2015/08/nodejs-cluster-tutorial/