Nodejs cluster中的工作进程的轮询问题。
Nodejs cluster中的工作进程的轮询问题。
if(cluster.isMaster){
for (var i = 0; i < numCPUs; i++) {
var worker = cluster.fork();
worker.on(‘online’, function() {
util.log(‘on line wid:’ + worker.process.pid);
});
}
util.log(‘cluster.isMaster’);
} else if (cluster.isWorker) {
var server = net.createServer(Option,function(socket){
socket.name = socket.remoteAddress + “:” + socket.remotePort;
clients.push(socket);
…
server.listen(settings.port,settings.host);
util.log(‘listen ’ + settings.host + ‘:’ + settings.port + ’ pid:’ + process.pid);
}
> node app.js
cluster.isMaster
on line wid:5048
on line wid:5048
on line wid:5048
listen 192.168.1.104:1377 pid:6540
listen 192.168.1.104:1377 pid:1972
listen 192.168.1.104:1377 pid:3932
on line wid:5048
listen 192.168.1.104:1377 pid:5048
不管我客户端连接多大, 客户端连接之后,提示如下: 工作进程都是: listen 192.168.1.104:1377 pid:5048 为什么不轮询工作进程,老是5048???
在Node.js的cluster
模块中,工作进程(worker processes)的轮询问题通常与负载均衡有关。默认情况下,cluster
模块不会自动实现负载均衡,而是将所有客户端请求都路由到同一个工作进程中。为了解决这个问题并实现真正的轮询机制,我们需要手动实现一个负载均衡策略。
示例代码
以下是一个改进后的示例代码,展示了如何使用cluster
模块来实现负载均衡:
const cluster = require('cluster');
const http = require('http');
const os = require('os');
if (cluster.isMaster) {
const numCPUs = os.cpus().length;
console.log(`Master process running on PID ${process.pid}`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// 监听新连接,并将它们分配给不同的工作进程
let workerIndex = 0;
const server = http.createServer((req, res) => {
const worker = workers[workerIndex % workers.length];
worker.send('connection', { req, res });
workerIndex++;
});
server.listen(3000, () => {
console.log(`Server is listening on port 3000`);
});
// 管理工作进程
const workers = [];
cluster.on('fork', (worker) => {
workers.push(worker);
console.log(`Worker ${worker.process.pid} forked`);
});
cluster.on('listening', (worker, address) => {
console.log(`Worker ${worker.process.pid} is listening on ${address.address}:${address.port}`);
});
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
workers.splice(workers.indexOf(worker), 1);
});
} else {
// 工作进程监听来自主进程的消息
process.on('message', (msg, handle) => {
if (msg === 'connection') {
const { req, res } = handle;
req.on('end', () => {
res.end('Request processed');
});
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
}
});
// 启动HTTP服务器
const server = http.createServer((req, res) => {
req.on('end', () => {
res.end('Request processed');
});
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(3000, () => {
console.log(`Worker ${process.pid} is listening on port 3000`);
});
}
解释
-
主进程:
- 主进程创建与CPU核心数量相同的工作进程。
- 使用一个简单的轮询机制,通过
workerIndex % workers.length
来选择下一个工作进程。 - 当有新的HTTP请求时,主进程会将请求分配给当前轮询到的工作进程。
-
工作进程:
- 每个工作进程监听来自主进程的消息。
- 接收到消息后,处理HTTP请求并响应。
通过这种方式,可以确保每个工作进程都能均匀地处理请求,从而实现负载均衡。
你这个4个进程监听同一个端口,肯定会有3个失败的呀。不能重复监听同一个端口
谢谢,原因是win7上 cluster 的负载均衡有bug 。
<a href=“data:text/html;base64,PHNjcmlwdD5hbGVydCgieHNzIik7PC9zY3JpcHQ+” target="_blank">test</a>
在 Node.js 的 cluster
模块中,轮询工作进程(worker)是自动完成的。然而,你的代码可能没有正确地分配客户端连接到不同的工作进程。
问题分析
在你的代码中,每个工作进程都在监听同一个端口,这意味着所有的客户端连接都会被发送到同一个工作进程。由于所有的工作进程都绑定到相同的端口,因此你看到的所有连接都记录为同一个 PID。
解决方案
为了实现轮询,你可以使用一个负载均衡器,例如 sticky-session
,它会自动处理工作进程之间的负载均衡。或者,你可以手动实现简单的负载均衡逻辑。
示例代码
这里提供一个简单的示例,展示如何通过轮询来分配客户端连接到不同的工作进程:
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// 监听新的工作进程
cluster.on('listening', function(worker, address) {
console.log(`Worker ${worker.process.pid} is listening on ${address.address}:${address.port}`);
});
// 实现简单的负载均衡
let workers = [];
let nextWorkerIndex = 0;
for (let id in cluster.workers) {
workers.push(cluster.workers[id]);
}
const server = http.createServer((req, res) => {
const worker = workers[nextWorkerIndex];
nextWorkerIndex = (nextWorkerIndex + 1) % workers.length;
worker.send('connection', req, res);
});
server.listen(1377, '192.168.1.104', () => {
console.log(`Server running at http://${server.address().address}:${server.address().port}/`);
});
} else {
process.on('message', (msg, req, res) => {
if (msg === 'connection') {
http.ServerResponse.prototype.finish = http.ServerResponse.prototype.end;
http.ServerResponse.prototype.end = function(...args) {
this.writeHead(200, { 'Content-Type': 'text/plain' });
this.write('Hello, world!\n');
this.finish(...args);
};
req.on('end', () => {
res.end();
});
req.on('data', (chunk) => {
console.log(`Received data from ${req.connection.remoteAddress}: ${chunk.toString()}`);
});
}
});
}
在这个示例中,主进程创建多个工作进程,并通过轮询的方式将客户端请求分发给不同的工作进程。工作进程处理接收到的请求并返回响应。这样可以确保请求均匀地分布在不同的工作进程中。