Node.js cluster模块详解

发布于:2025-04-13 ⋅ 阅读:(20) ⋅ 点赞:(0)

Node.js cluster 模块详解

cluster 模块允许你轻松创建共享同一服务器端口的子进程(worker),充分利用多核 CPU 的性能。它是 Node.js 实现高并发的重要工具。

核心概念

  1. 主进程(Master):负责管理工作进程,通常不处理实际请求
  2. 工作进程(Worker):实际处理请求的子进程
  3. 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: 如果是主进程则为 true
  • cluster.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);
}

性能注意事项

  1. 负载均衡:Node.js 的 cluster 模块默认使用轮询调度(除了 Windows)
  2. 状态共享:工作进程之间不共享内存,需要通过 IPC 或外部存储(如 Redis)共享状态
  3. 长连接:对于 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} 已启动`);
  });
}

常见问题解决方案

  1. 工作进程崩溃:监听 exit 事件并自动重启
  2. 零停机部署:使用 SIGUSR2 信号实现优雅重启
  3. 会话保持:使用粘性会话(sticky session)或外部会话存储

总结

cluster 模块是 Node.js 实现多进程的核心模块,能够显著提升应用的并发处理能力。通过合理配置和管理工作进程,可以构建高可用、高性能的 Node.js 应用。