Nodejs 如何再cluster.fork后关闭master listen的socket
Nodejs 如何再cluster.fork后关闭master listen的socket
我想通过cluster管理多个worker, 每个worker 分别listen一个端口。 我发现worker再listen一个端口时候会首先问master是否已经监听, 若无则master也监听, 然后pass handle到worker。 这样问题是master和worker会同时监听一个端口。
这样的话会增大master的负载, 同时我的master不想负责此工作。 所以我想再worker listen后再master中close掉那个handle。 找了很多doc都没有发现如何做, 不知道大家有没有类似经验
Node.js 如何在 cluster.fork
后关闭 master 的 listen socket
问题描述
你希望使用 cluster
模块来管理多个 worker,并且每个 worker 要监听不同的端口。然而,当你启动 worker 并尝试监听端口时,发现 master 也会监听相同的端口。这不仅增加了 master 的负载,而且你希望 master 不要参与这部分工作。
解决方案
你可以通过以下步骤来解决这个问题:
- 让 master 不监听任何端口:首先确保 master 不监听任何端口。
- 在 worker 中手动传递监听句柄:worker 可以通过
process.send
将监听句柄传递给 master,然后 master 关闭该句柄。
以下是具体的实现代码:
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
// 创建一个 HTTP 服务器实例
const server = http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
});
// 让 worker fork
const numWorkers = 2;
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}
// 监听 worker 的消息
cluster.on('message', (worker, message, handle) => {
if (message === 'listening') {
// 当 worker 开始监听时,关闭 master 的监听句柄
handle.close(() => {
console.log(`Closed the listening socket for worker ${worker.id}`);
});
}
});
} else {
// Worker process
const workerPort = 3000 + cluster.worker.id;
// 创建一个 HTTP 服务器实例
const workerServer = http.createServer((req, res) => {
res.writeHead(200);
res.end(`Worker ${cluster.worker.id} says hello\n`);
});
// 绑定到指定的端口
workerServer.listen(workerPort);
// 发送消息给 master 表示 worker 已经开始监听
process.send('listening');
}
解释
-
Master 部分:
- 创建一个 HTTP 服务器实例,但不调用
.listen()
方法,因此 master 不会实际监听任何端口。 - 使用
cluster.fork()
方法创建 worker。 - 监听
cluster
模块的message
事件,当 worker 发送消息时处理。如果消息为'listening'
,则关闭 worker 的监听句柄。
- 创建一个 HTTP 服务器实例,但不调用
-
Worker 部分:
- 创建一个 HTTP 服务器实例,并绑定到特定的端口(例如
3000 + cluster.worker.id
)。 - 使用
process.send('listening')
将消息发送给 master,通知 master worker 已经开始监听。
- 创建一个 HTTP 服务器实例,并绑定到特定的端口(例如
通过这种方式,你可以确保 master 不会监听任何端口,而 worker 会在独立的端口上运行。
为了实现你的需求,你可以使用 Node.js 的 cluster
模块,并且在每个 worker 启动之后关闭 master 的监听 socket。以下是一个示例代码来说明如何操作:
示例代码
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < 2; i++) {
cluster.fork();
}
// Wait for all workers to be ready
let workerCount = Object.keys(cluster.workers).length;
cluster.on('fork', () => {
if (--workerCount === 0) {
// All workers are ready, close the master's server
server.close(() => {
console.log('Master server closed');
});
}
});
// Create a server for the master
const server = http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
});
server.listen(3000, () => {
console.log('Master server listening on port 3000');
});
} 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 from worker ' + process.pid);
}).listen(3001);
console.log(`Worker ${process.pid} started`);
}
解释
-
Master 和 Worker 初始化:
- 在
master
进程中,我们创建了一个 HTTP 服务器并将其绑定到端口3000
。 - 使用
cluster.fork()
创建了两个 worker 进程。
- 在
-
监听所有 worker 准备就绪:
- 使用
cluster.on('fork')
监听 worker 进程的创建事件。 - 当所有 worker 都启动后(
workerCount === 0
),我们关闭 master 的 HTTP 服务器。
- 使用
-
Worker 端:
- 每个 worker 创建自己的 HTTP 服务器,并绑定到不同的端口(例如
3001
)。 - 这确保了 worker 负责处理请求,而 master 只负责初始化 worker。
- 每个 worker 创建自己的 HTTP 服务器,并绑定到不同的端口(例如
这样,master 就不会处理任何请求,只负责初始化 worker。当所有 worker 都准备好后,master 的 HTTP 服务器就会关闭。