cluster模块
Node.js 的 cluster
模块允许开发者利用多核 CPU 的能力,通过创建子进程(worker)来并行处理任务。它基于主从模型,主进程负责管理子进程,子进程共享同一个端口并独立处理请求,显著提升服务器的吞吐量和可靠性。
cluster 模块的核心概念
cluster
模块的核心是主进程(master)和子进程(worker)的分工协作。主进程不直接处理业务逻辑,而是负责调度和管理子进程;子进程则是实际执行代码的单元。以下是一个最简单的示例:
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.createServer((req, res) => {
res.writeHead(200);
res.end('你好世界\n');
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
进程间通信
虽然子进程独立运行,但 cluster
模块提供了进程间通信(IPC)机制。主进程和子进程可以通过 process.send()
和 message
事件交换数据。例如:
// 主进程代码
cluster.on('fork', (worker) => {
worker.send({ type: 'greeting', msg: 'Hello from master' });
});
// 子进程代码
process.on('message', (msg) => {
if (msg.type === 'greeting') {
console.log(`Worker ${process.pid} received: ${msg.msg}`);
}
});
负载均衡策略
默认情况下,cluster
模块采用轮询策略分配请求(Windows 除外)。Node.js 支持通过 cluster.schedulingPolicy
修改策略:
const cluster = require('cluster');
cluster.schedulingPolicy = cluster.SCHED_RR; // 轮询(Round-Robin)
// 或
cluster.schedulingPolicy = cluster.SCHED_NONE; // 由操作系统决定
实际应用场景
HTTP 服务器集群
构建高并发 HTTP 服务时,cluster
能有效避免单进程阻塞:
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
const cpuCount = require('os').cpus().length;
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
// 模拟 CPU 密集型任务
let count = 0;
for (let i = 0; i < 1e7; i++) { count++ }
res.end(`Worker ${process.pid} handled request`);
}).listen(3000);
}
零停机重启
通过信号处理和进程管理,可以实现不中断服务的重启:
// 主进程
process.on('SIGUSR2', () => {
const workers = Object.values(cluster.workers);
const restartWorker = (i) => {
if (i >= workers.length) return;
const worker = workers[i];
worker.on('exit', () => {
if (!worker.exitedAfterDisconnect) return;
const newWorker = cluster.fork();
newWorker.on('listening', () => restartWorker(i + 1));
});
worker.disconnect();
};
restartWorker(0);
});
高级特性与注意事项
共享端口机制
所有子进程通过 net
模块的 IPC 通道共享同一个端口,底层由主进程的 round-robin
处理器分配连接。这不同于直接使用 child_process
模块时每个子进程需要绑定不同端口的情况。
状态共享问题
由于子进程内存隔离,需要避免直接修改全局状态。解决方案包括:
- 使用 Redis 等外部存储
- 通过主进程协调状态
- 采用无状态设计
// 错误示例:子进程独立计数
let requestCount = 0;
http.createServer((req, res) => {
requestCount++;
res.end(`Total requests: ${requestCount}`); // 每个worker有独立计数
}).listen(8080);
错误处理实践
必须监听子进程的异常事件,否则未捕获的异常会导致进程退出:
cluster.on('exit', (worker, code, signal) => {
console.error(`Worker ${worker.process.pid} died`);
if (!worker.exitedAfterDisconnect) {
cluster.fork(); // 自动重启
}
});
// 子进程中
process.on('uncaughtException', (err) => {
console.error('Caught exception:', err);
process.exit(1); // 主动退出以便主进程重启
});
性能优化技巧
进程数量控制
虽然通常按 CPU 核心数创建子进程,但 I/O 密集型场景可适当增加:
const totalWorkers = require('os').cpus().length * (isIOIntensive ? 1.5 : 1);
粘性会话处理
某些需要会话保持的场景(如 WebSocket),可通过 sticky-session
包实现:
const sticky = require('sticky-session');
const server = http.createServer((req, res) => { /* ... */ });
sticky.listen(server, 3000, {
workers: 4,
env: { NODE_ENV: 'production' }
});
与 PM2 等工具的比较
虽然 PM2 等进程管理器也提供集群功能,但 cluster
模块的优势在于:
- 无需额外依赖
- 更精细的控制逻辑
- 深度集成于 Node.js 运行时
典型 PM2 集群配置:
pm2 start app.js -i max # 自动根据CPU核心数启动集群
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:child_process模块
下一篇:进程间通信