众所周知,Node.js是单线程的,一个单独的Node.js进程无法充分利用多核。Node.js从v0.6.0开始,新增cluster模块,让Node.js开发Web服务时,很方便的做到充分利用多核机器。
充分利用多核的思路是:使用多个进程处理业务。cluster模块封装了创建子进程、进程间通信、服务负载均衡。有两类进程,master进程和worker进程,master进程是主控进程,它负责启动worker进程,worker是子进程、干活的进程。
简单的demo代码如下:
/* * cluster module's example * 2016.02.16 * cswuyg * */ 'use strict'; var cluster = require('cluster'); var http = require('http'); var cpuCount = require('os').cpus().length; if (cluster.isMaster) { for (var i = 0; i < cpuCount; ++i) { cluster.fork(); } } else { http.createServer(function(req, res) { res.writeHead(200); res.end('hello world '); console.log(cluster.worker.id); }).listen(8000); }
注意和其它:
1、负载均衡问题
一个web请求过来,是给worker进程A处理,还是worker进程B处理呢?怎么保证大家均等的干活呢? 这就是负载均衡的问题。
当前有两种可选的方法来做负载均衡。
早期的cluster是各个worker进程自己去监听socket端口,由操作系统去唤醒worker进程,大家可能很容易认为操作系统会随机的选择worker进程,于是就实现了服务的负载均衡。但实际上,像Linux操作系统总是唤醒某几个进程,因为对于系统来说,上下文切换时很昂贵的操作,唤醒最近被唤醒的进程是比较好的选择。早期的这种方式负载是很不均衡的。
从0.11.2版本开始,cluster开始增加了round-robin模式做负载均衡:master进程负责监听,收到请求后转发给worker进程,多个worker进程轮流干活。
round-robin是当前cluster的默认负载均衡处理模式(除了windows平台),如果要回到之前的模式,有两种方式,
(1)可以在cluster加载之后未调用其它cluster函数之前执行:cluster.schedulingPolicy = cluster.SCHED_NONE; 来设定。
(2)设置环境变量NODE_CLUSTER_SCHED_POLICY="none",例如:NODE_CLUSTER_SCHED_POLICY="none" node b.js > a.log。 可选值为:'rr'和'none'。
2、进程监控问题
master进程不会自动管理worker进程的生死,如果worker被外界杀掉了,不会自动重启,只会给master进程发送‘exit’消息,开发者需要自己做好管理。
3、数据共享问题
各个worker进程之间是独立的,为了让多个worker进程共享数据(譬如用户session),一般的做法是在Node.js之外再搭建一个数据库,多个worker进程通过数据库做数据共享。
4、一些测试和练习代码
官方资料:https://nodejs.org/api/cluster.html
学习资料:http://www.infoq.com/cn/articles/nodejs-cluster-round-robin-load-balancing
nodejs changelog:https://github.com/nodejs/node/blob/v4.3.0/CHANGELOG.md