NodeJS之cluster

2019/8/27 NodeJS

🌙 why

nodejs 无法 使用多核CPU,只能使用单核CPU,但是nodejs提供了cluster模块,可以创建多个子进程,实现多核CPU的利用,从而提高nodejs的性能。

🌙 how

🌙 cluster 模块的使用方法

cluster 模块是 Node.js 提供的一个内置模块,用于创建多进程应用程序,从而充分利用多核 CPU 的性能。通过 cluster,你可以创建多个工作进程(worker),这些工作进程可以共享同一个端口,处理网络请求等任务。

🌙 1. 基本概念

  • 主进程(Master Process):负责管理和启动工作进程。
  • 工作进程(Worker Process):实际处理客户端请求的工作单元。

🌙 2. 为什么需要 cluster

  • 充分利用多核 CPU:Node.js 是单线程的,只能利用一个 CPU 核心。通过 cluster,可以在多核系统上启动多个工作进程,从而提高应用的性能和吞吐量。
  • 负载均衡cluster 模块会自动将传入的连接分发给不同的工作进程,实现简单的负载均衡。

🌙 3. 使用步骤

🌙 3.1 引入 cluster 模块
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
1
2
3
🌙 3.2 判断是否为主进程
if (cluster.isPrimary) {
  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 server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`你好,我是工作进程 ${process.pid}\n`);
  });

  server.listen(3000);
  console.log(`工作进程 ${process.pid} 已启动`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
🌙 3.3 完整示例
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  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 server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`你好,我是工作进程 ${process.pid}\n`);
  });

  server.listen(3000);
  console.log(`工作进程 ${process.pid} 已启动`);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

🌙 4. 关键方法和事件

  • cluster.fork():创建并启动一个新的工作进程。
  • cluster.isPrimary:判断当前进程是否为主进程。
  • cluster.on('exit', callback):监听工作进程退出事件,可以选择重启新的工作进程。
  • worker.disconnect():断开工作进程与主进程的连接。
  • worker.kill():强制终止工作进程。

🌙 5. 注意事项

  • 资源共享:所有工作进程共享同一份代码和配置文件,但它们有独立的内存空间。
  • 负载均衡cluster 模块默认使用轮询算法来分配连接到不同的工作进程。
  • 错误处理:确保正确处理工作进程的退出事件,避免因某个工作进程崩溃而导致整个应用不可用。

🌙 6. 高级用法

🌙 6.1 主进程与工作进程通信

可以通过消息传递机制在主进程和工作进程之间进行通信:

// 主进程发送消息给所有工作进程
Object.keys(cluster.workers).forEach(id => {
  cluster.workers[id].send({ action: 'message', content: 'Hello from master' });
});

// 工作进程接收消息
process.on('message', msg => {
  console.log(`收到消息: ${msg.content}`);
});
1
2
3
4
5
6
7
8
9
🌙 6.2 动态调整工作进程数量

可以根据服务器负载动态调整工作进程的数量:

if (cluster.isPrimary) {
  let workerCount = numCPUs;

  setInterval(() => {
    // 根据某些条件调整 workerCount
    if (shouldIncreaseWorkers()) {
      cluster.fork();
      workerCount++;
    } else if (shouldDecreaseWorkers() && workerCount > 1) {
      Object.keys(cluster.workers)[0].kill();
      workerCount--;
    }
  }, 1000);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

🌙 7. 总结

cluster 模块为 Node.js 应用提供了强大的多进程支持,能够有效利用多核 CPU 提高应用性能。通过合理使用 cluster,你可以构建更加高效、可靠的网络服务。