Node.js cluster模块相关笔记

okgoes 2023-05-09 13:07:20
Categories: Tags:

cluster

Node.js的单个实例在单个线程中运行。 要利用多核系统,用户有时会想启动一个Node.js进程集群来处理负载。
cluster模块可以轻松创建全部共享服务器端口的子进程。

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
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);

// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}

cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);

console.log(`Worker ${process.pid} started`);
}

运行Node.js,所有的工作进程将共享8000端口

1
2
3
4
5
6
7
$ node server.js
Master 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started

请注意,在Windows上,尚不可能在工作进程中设置命名管道服务。

cluster如何工作

使用child_process.fork()方法产生工作进程,以便它们可以通过IPC与父进程通信并来回传递服务器句柄。

cluster模块支持两种分配传入连接的方法。

第一种方法(除Windows以外的所有平台上的默认方法)都是循环法,即主进程在端口上进行侦听,接受新连接并以循环方式在工作进程之间进行分配,其中一些已构建智能避免过载工作进程。

第二种方法是主进程创建侦听套接字并将其发送给感兴趣的工作进程。工作进程然后直接接受传入连接。

理论上,第二种方法应该是最好的。然而,在实践中,由于操作系统调度器的变幻莫测,分配趋于非常不平衡。已经观察到负载超过70%的连接只有两个过程,总共有八个。

因为server.listen()将大部分工作交给了主进程,所以在正常的Node.js进程和集群工作进程之间的行为有三种情况:

  1. server.listen({fd:7})因为消息被传递给主进程,父进程中的文件描述符7将被监听,并且该句柄传递给工作进程,而不是监听工作进程的文件描述符7的引用。
  2. server.listen(句柄)明确地监听句柄会导致工作进程使用提供的句柄,而不是与主进程通信。
  3. server.listen(0)通常,这将导致服务器侦听随机端口。但是,在集群中,每个工作人员每次收听(0)时都会收到相同的“随机”端口。实质上,这个端口在第一时间是随机的,但此后可以预见。要监听唯一端口,请根据群集工作器ID生成端口号。

Node.js不提供路由逻辑。因此,设计一个应用程序非常重要,因为它不会过度依赖内存数据对象,如会话和登录等。

因为工作进程都是独立的进程,所以他们可以根据程序的需要被杀死或重新生成,而不会影响其他工作进程。只要有一些工作进程还活着,服务器将继续接受连接。如果没有工作进程活着,现有的连接将被丢弃,新的连接将被拒绝。但是,Node.js不会自动管理工作进程的数量。根据自己的需要管理工作进程池是应用程序的责任。

虽然cluster模块的主要用例是联网,但它也可以用于需要工作进程的其他用例。

类:Worker

新增于v0.7.0
Worker对象包含有关工作进程的所有公共信息和方法。 在主进程中可以使用cluster.workers获得。 在工作进程中,可以使用cluster.worker获得。

Event: ‘disconnect’

新增于v0.7.7
类似于cluster.on(’disconnect’)事件,但是特定于此worker。

1
2
3
4
cluster.fork().on('disconnect', () => {
// Worker has disconnected
});

Event: ‘error’

新增于v0.7.3
此事件与child_process.fork()提供的事件相同。
在工作进程中,process.on(’error’)也可以被使用。

Event: ‘exit’

新增于v0.11.2

1
2
3
4
5
6
7
8
9
10
11
const worker = cluster.fork();
worker.on('exit', (code, signal) => {
if (signal) {
console.log(`worker was killed by signal: ${signal}`);
} else if (code !== 0) {
console.log(`worker exited with error code: ${code}`);
} else {
console.log('worker success!');
}
});

Event: ‘listening’

新增于v0.7.0