进程
服务模型变迁
- 同步 QPS:1/N
- 复制进程 进程上限为 M, QPS:M/N
- 多线程 设线程占用资源未进程的 1/L,QPS:M * L / N
- 事件驱动
多进程架构
Master-Worker 模式(主从模式)
// worker.js
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello world\n');
}).listen(Math.round((1 + Math.random()) * 1000), '127.0.0.1');
// master.js
var fork = require('child_process').fork;
var cpus = require('os').cpus();
for (var i = 0; i < cpus.length; i++) {
fork('./worker.js');
}
创建子进程
- spawn() 启动一个子进程来执行命令
- exex() 启动一个子进程来执行命令,与 spawn() 不同的是其接口不同,有一个回调函数获知子进程的状况
- execFile() 启动一个子进程来执行可执行文件
- fork() 与 spawn() 类似,不同点在于它创建 Node 的子进程只需要指定要执行的 JS 文件模块即可
var cp = require('child_process'); cp.spawn('node', ['worker.js']); cp.exec('node worker.js', function (err, stdout, stderr) { // code }); cp.execFile('worker.js', function (err, stdout, stderr) { // code }); cp.fork('./worker.js');
进程间通信
- Node 中实现 IPC 通道的是管道技术(pipe)
// parent.js var cp = require('child_process'); var n = cp.fork(__dirname + '/sub.js'); n.on('message', function (m) { console.log('PARENT got message:', m); }); n.send({hello: 'world'}); // sub.js process.on('message', function (m) { console.log('CHILD got message:', m); }); process.send({foo: 'bar'});
句柄传递
- 句柄是一种可以标识资源的引用,内部包含了指向对象的文件描述符
- 句柄可以用来标识一个服务器端 socket 对象,一个客户端 socket 对象,一个 UDP 套接字,一个管道等
child.send(message, [sendHandle])
集群
进程事件
- send()
- kill()
- message
- error
- exit
- close
- disconnect
自动重启
- 通过监听子进程的 exit 事件来获知其退出的信息
// master.js var fork = require('child_process').fork; var cpus = require('os').cpus(); var server = require('net').createServer(); server.listen(1337); var workers = {}; var createWorker = function () { var worker = fork(__dirname + './worker.js'); // 退出时重新启动新的进程 worker.on('exit', function () { console.log(`Worker ${worker.pid} exited.`); delete workers[worker.pid]; createWorker(); }); worker.send('server', server); workers[worker.pid] = worker; console.log(`Create worker.pid: ${worker.pid}`); }; for (var i = 0; i < cpus.length; i++) { createWorker(); } // 进程自己退出时,让所有工作进程退出 process.on('exit', function () { for (var pid in workers) { workers[pid].kill(); } });
负载均衡
- Node 默认提供的机制是采用操作系统的抢占式策略
- 在 v0.11 中提供了一种新的策略 Round-Robin 轮叫调度
状态共享
- 三方数据存储,如数据库、磁盘文件、缓存服务,需定时轮询
- 主动通知,也需要一种机制获取数据的改变,不脱离轮询,但可以减少轮询的进程数量
Cluster
// cluster.js
var cluster = require('cluster');
cluster.setupMaster({
exec: 'worker.js'
});
var cpus = require('os').cpus();
for (var i = 0; i < cpus.length; i++) {
cluster.fork();
}
cluster 工作原理
- 本质是 child_process 和 net 的组合应用
cluster 事件
- fork
- online
- listening
- disconnect
- exit
- setup