阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > cluster模块

cluster模块

作者:陈川 阅读数:1492人阅读 分类: Node.js

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模块

下一篇:进程间通信

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌