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???


7 回复

在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`);
  });
}

解释

  1. 主进程

    • 主进程创建与CPU核心数量相同的工作进程。
    • 使用一个简单的轮询机制,通过workerIndex % workers.length来选择下一个工作进程。
    • 当有新的HTTP请求时,主进程会将请求分配给当前轮询到的工作进程。
  2. 工作进程

    • 每个工作进程监听来自主进程的消息。
    • 接收到消息后,处理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()}`);
      });
    }
  });
}

在这个示例中,主进程创建多个工作进程,并通过轮询的方式将客户端请求分发给不同的工作进程。工作进程处理接收到的请求并返回响应。这样可以确保请求均匀地分布在不同的工作进程中。

回到顶部