Node.js cluster
模块详解
cluster
模块允许你轻松创建共享同一服务器端口的子进程(worker),充分利用多核 CPU 的性能。它是 Node.js 实现高并发的重要工具。
核心概念
- 主进程(Master):负责管理工作进程,通常不处理实际请求
- 工作进程(Worker):实际处理请求的子进程
- IPC 通信:主进程和工作进程之间通过进程间通信(IPC)交换消息
基本使用
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 衍生工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 工作进程可以共享任何 TCP 连接
// 在本例子中,它是一个 HTTP 服务器
http.createServer((req, res) => {
res.writeHead(200);
res.end('你好世界\n');
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
主要 API
cluster.isMaster / cluster.isWorker
cluster.isMaster
: 如果是主进程则为 truecluster.isWorker
: 如果是工作进程则为 true
cluster.fork([env])
- 衍生一个新的工作进程
- 可以传入环境变量对象
env
- 返回
Worker
对象
cluster.setupMaster([settings])
- 修改默认的
fork
行为 settings
可选参数:exec
: 工作进程文件路径args
: 传递给工作进程的参数silent
: 是否将输出发送到父进程的 stdio
cluster.worker
- 当前工作进程对象的引用(仅在子进程中可用)
cluster.workers
- 存储所有活跃工作进程的哈希表
- 键是工作进程 ID,值是
Worker
对象
Worker 类
worker.id
- 每个新创建的工作进程都有唯一的 ID
worker.process
- 工作进程的
ChildProcess
对象
worker.send(message[, sendHandle][, callback])
- 向工作进程发送消息
- 可以通过
sendHandle
发送句柄
worker.kill([signal=‘SIGTERM’])
- 杀死工作进程
worker.disconnect()
- 断开工作进程与主进程的连接
事件
cluster.on(‘fork’, worker)
- 当新的工作进程被 fork 时触发
cluster.on(‘online’, worker)
- 当工作进程开始运行后触发
cluster.on(‘listening’, worker, address)
- 当工作进程调用
listen()
后触发
cluster.on(‘disconnect’, worker)
- 当工作进程的 IPC 通道断开时触发
cluster.on(‘exit’, worker, code, signal)
- 当工作进程退出时触发
cluster.on(‘message’, worker, message, handle)
- 当工作进程发送消息时触发
高级特性
1. 进程间通信
if (cluster.isMaster) {
const worker = cluster.fork();
worker.send('主进程发送的消息');
worker.on('message', (msg) => {
console.log('收到工作进程消息:', msg);
});
} else {
process.on('message', (msg) => {
console.log('收到主进程消息:', msg);
process.send('工作进程回复');
});
}
2. 优雅重启
if (cluster.isMaster) {
// 启动工作进程
const worker = cluster.fork();
// 收到重启信号
process.on('SIGUSR2', () => {
const newWorker = cluster.fork();
newWorker.on('listening', () => {
worker.kill('SIGTERM');
});
});
} else {
require('./server'); // 你的应用代码
}
3. 共享服务器端口
多个工作进程可以共享同一个端口:
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
const net = require('net');
net.createServer((socket) => {
socket.end('由工作进程 ' + process.pid + ' 处理');
}).listen(8000);
}
性能注意事项
- 负载均衡:Node.js 的 cluster 模块默认使用轮询调度(除了 Windows)
- 状态共享:工作进程之间不共享内存,需要通过 IPC 或外部存储(如 Redis)共享状态
- 长连接:对于 WebSocket 等长连接应用,需要确保同一客户端始终连接到同一工作进程
实际应用示例
Express 应用集群化
const cluster = require('cluster');
const express = require('express');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
// 衍生工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
// 自动重启
cluster.fork();
});
} else {
const app = express();
app.get('/', (req, res) => {
res.send(`由工作进程 ${process.pid} 处理`);
});
app.listen(3000, () => {
console.log(`工作进程 ${process.pid} 已启动`);
});
}
常见问题解决方案
- 工作进程崩溃:监听
exit
事件并自动重启 - 零停机部署:使用
SIGUSR2
信号实现优雅重启 - 会话保持:使用粘性会话(sticky session)或外部会话存储
总结
cluster
模块是 Node.js 实现多进程的核心模块,能够显著提升应用的并发处理能力。通过合理配置和管理工作进程,可以构建高可用、高性能的 Node.js 应用。