Node.js Cluster 模块

Java FileNode.js 内置模块


Node.js 的 cluster 模块允许你轻松创建共享同一服务器端口的子进程(worker processes)。由于 Node.js 是单线程的,cluster 模块可以帮助我们充分利用多核 CPU 系统的性能。

简单来说,cluster 模块就像是一家餐厅的经理,它创建多个服务员(worker)来处理顾客(请求),而不是让一个服务员处理所有顾客。


为什么需要 Cluster 模块?

  1. 提高性能:现代 CPU 通常有多个核心,但 Node.js 默认只使用一个核心。cluster 模块可以让你利用所有可用的 CPU 核心。

  2. 提高可靠性:如果一个 worker 崩溃了,其他 worker 可以继续处理请求,主进程可以重新启动崩溃的 worker。

  3. 零停机时间:可以逐个重启 worker 来实现代码更新,而不会中断服务。


Cluster 模块基础用法

实例

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);

  // 衍生 worker 进程
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} 已退出`);
  });
} else {
  // Worker 可以共享同一个 TCP 连接
  // 这里是一个 HTTP 服务器
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('你好世界\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} 已启动`);
}

核心概念解析

主进程(Master Process)

  • 负责管理所有 worker 进程
  • 通常不处理实际请求
  • 可以监听 worker 的各种事件

Worker 进程

  • 实际处理请求的子进程
  • 每个 worker 都是独立的 Node.js 进程
  • 共享同一个服务器端口

Cluster 模块常用 API

cluster.fork()

创建一个新的 worker 进程。调用这个方法会返回一个 worker 对象。

cluster.isMaster

如果是主进程,则为 true

cluster.isWorker

如果是 worker 进程,则为 true

cluster.workers

包含所有活跃 worker 对象的哈希表,以 worker.id 作为键名。


实际应用场景

1. 负载均衡

实例

// 在主进程中
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  require('./app'); // 你的应用入口文件
}

2. 优雅重启

实例

cluster.on('exit', (worker, code, signal) => {
  console.log(`Worker ${worker.process.pid} 退出`);
  // 可以在这里重新 fork 一个新的 worker
  cluster.fork();
});

3. 进程间通信

实例

// 主进程发送消息
worker.send('Hello worker!');

// Worker 接收消息
process.on('message', (msg) => {
  console.log(`Worker ${process.pid} 收到消息: ${msg}`);
});

性能优化技巧

  1. 根据 CPU 核心数创建 worker:通常建议 worker 数量等于 CPU 核心数。

  2. 共享端口:所有 worker 共享同一个端口,操作系统会自动分配请求到不同的 worker。

  3. 共享连接:对于长连接(如 WebSocket),需要考虑连接如何分配到不同的 worker。

  4. 共享状态:worker 之间不共享内存,需要使用 Redis 等外部存储来共享状态。


常见问题与解决方案

1. 内存泄漏

每个 worker 是独立进程,一个 worker 的内存泄漏不会影响其他 worker,但需要监控并重启异常的 worker。

2. 会话保持

如果需要会话保持,可以使用粘性会话(sticky session)或将会话数据存储在外部(如 Redis)。

3. 文件描述符限制

大量 worker 可能导致文件描述符耗尽,需要调整系统限制:

实例

ulimit -n 10000  # 设置文件描述符限制

Cluster 模块的替代方案

虽然 cluster 模块很强大,但也有其他选择:

  1. PM2:进程管理器,内置负载均衡和监控功能
  2. Nginx:反向代理,可以在多个 Node.js 实例间负载均衡
  3. Kubernete:容器编排系统,可以自动扩展 Node.js 服务

总结

Node.js 的 cluster 模块是构建高性能、高可用性网络服务的重要工具。通过创建多个 worker 进程,我们可以:

  1. 充分利用多核 CPU 的性能
  2. 提高应用的可靠性
  3. 实现零停机部署

虽然设置和管理多进程应用比单进程复杂,但对于生产环境中的 Node.js 应用来说,使用 cluster 模块或类似的解决方案几乎是必须的。

希望这篇指南能帮助你理解和使用 Node.js 的 cluster 模块!

Java FileNode.js 内置模块