nodejs中怎么利用cluster实现多进程

2023-05-04,

本篇文章为大家展示了nodejs中怎么利用cluster实现多进程,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

cluster
  • node进行多进程的模块;

属性和方法
  1. isMaster属性,返回是不是主进程,boolean值;

  2. isWorker属性, 返回该进程是不是工作进程;

  3. fork()方法,只能通过主进程调用,衍生出一个新的worker子进程,返回worker对象;

  4. setupMaster([setting])方法,用于修改fork的默认行为,一旦调用,将会按照cluster.settings进行设置;

  5. settings属性;用于配置;

  • 参数exec:worker文件路径,

  • args:传递给worker的参数;

  • execArgv: 传递给nodejs可执行文件的参数列表;

const cluster = require('cluster');
const cpuNums = require('os').cpus().length;
const http = require('http');

if (cluster.isMaster) {
  console.log(cpuNums);
  for (var i = 0; i < cpuNums; i++) {
    cluster.fork(); // 相当于node main.js,重新执行自己
    // 和process_child相比,不用重新创建child.js,
  }
  
  cluster.on('fork', worker => {
    console.log(`主进程fork了一个worker,pid为${worker.process.pid}`)
  })
  
  cluster.on('listening', worker => {
    console.log(`主进程fork了一个worker,pid为${worker.process.pid}`)
  })
  
  cluster.on('message', data => {
      console.log('主进程接收到了子进程消息为:',data)
  })
  
  Object.keys(cluster.workers).forEach(item => {
    cluster.workers[item].on('message', data => {
      console.log(data);
    });
  });
  
  cluster.on('disconnect', (worker) => {
    console.log('有工作进程退出了',worker.process.pid)
  })

} else {

  http.createServer((req, res) => {
    res.end('hello')
  }).listen(8001, () =>{
      console.log('child server is runing')
  })    
  
  console.log('我是子进程');
  
  process.send('子说:你好');
}
事件
  1. fork事件,当新的工作进程被fork时触发,可以用来记录工作进程活动;

  2. listening事件,当一个工作进程调用listen()后触发,事件处理器两个参数:worker:工作进程对象, address:包含了链接属性

  • 只有http的服务的listen事件才能触发此事件

  1. message事件,监听子进程的消息;当cluster主进程接收任何工作进程发送的消息时触发;

  • 比较特殊需要在单独的worker上监听;

  1. online事件,

  2. disconnect事件,当工作进程断开时调用;

  3. exit事件,

  4. setup事件,cluster.setupMaster()执行后触发;

cluster多进程模型
  • 每个worker进程通过使用cluster.fork()函数,基于IPC(Inter-Process-Communication),实现与master进程间通信;

那通过child_process.fork()直接创建不就可以了,为什么要通过cluster

这种方式只实现了多进程,多进程运行还涉及父子进程通信,子进程管理,以及负载均衡等问题,这些特性cluster已经做了处理了;

惊群现象
  • 多个进程间会竞争一个accept连接,产生惊群现象,效率比较低;

  • 由于无法控制一个新的连接由哪个进程来处理,导致worker进程间负载不均衡;

master.js

const net = require('net'); // 是最基础的网络模块,http的基础就是网络模块,最底层是socket
const fork = require('child_process').fork; // 惊群
var handle = net._createServerHandle('0.0.0.0', 5000); // net模块创建一个服务,绑定到3000端口,返回一个callback
for (var i = 0; i < 4; i++) {
  console.log('fork', i);
  fork('./worket.js').send({}, handle); // 主进程fork子进程,send信息
}

worker.js

const net = require('net');
process.on('message', (m, handle) => { // 子进程接收到master信息
  // master接收客户端的请求,worker去响应
  start(handle);
});

var buf = 'hello nodejs';
var res =
  ['HTTP/1.1 200 OK', 'content-length' + buf.length].join('\r\n') +
  ' \r\n\r\n' +
  buf;

var data = {};

function start(server) {
  // 响应逻辑,重点关注惊群效果,计数
  server.listen();
  server.onconnection = function(err, hand) {
    var pid = process.pid;
    if (!data[pid]) {
      data[pid] = 0;
    }
    data[pid]++;
    console.log('get a connection on worker,pid = %d', process.pid, data[pid]);
    var socket = net.Socket({
      handle: hand
    });
    socket.readable = socket.writable = true; // 修改socket的读写属性
    socket.end(res);
  };
}
nginx proxy
  • Nginx 是俄罗斯人编写的十分轻量级的http服务器,是一个高性能的HTTP和反向代理服务器,异步非阻塞I/O,而且能够高并发;

  • 正向代理:客户端为代理,服务端不知道代理是谁;

  • 反向代理:服务器为代理,客户端不知道代理是谁;

  • nginx的实际应用场景: 比较适合稳定的服务

    • 静态资源服务器:js,css, html

    • 企业级集群

守护进程:退出命令窗口之后,服务一直处于运行状态;

cluster多进程调度模型
  • cluster是由master监听请求,在通过round-robin算法分发给各个worker,避免了惊群现象的发生;

round-robin 轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器;

cluster-model.js

const net = require('net');
const fork = require('child_process').fork; // cluster 简单版本,cluster就是基于child_process去封装的;

var workers = [];
for (var i = 0; i < 4; i++) {
  workers.push(fork('./child')); // cluster workers
}
var handle = net._createServerHandle('0.0.0.0', 3001); // master
handle.listen();
handle.onconnection = function(err, handle) {
  var worker = workers.pop();
  worker.send({}, handle);
  workers.unshift(worker); // 通过pop 和 unshift实现一个简单的轮询
};

child.js

const net = require('net');
process.on('message', (m, handle) => {
  debugger;
  start(handle);
});

var buf = 'hello cluster';
var res =
  ['HTTP/1.1 200 OK', 'content-length' + buf.length].join('\r\n') +
  '\r\n\r\n' +
  buf;

function start(handle) {
  console.log('get a worker on server,pid = ' + process.pid);
  var socket = net.Socket({
    handle
  });
  socket.readable = socket.writable = true; // 修改socket的读写属性
  socket.end(res);
}
cluster中的优雅退出
  1. 关闭异常worker进程所有的TCP server(将已有的快速断开,且不再接受新的连接),断开和Master的IPC通道,不再接受新的用户请求;

  2. Master立刻fork一个新的worker进程,保证总的进程数量不变;

  3. 异常worker等待一段时间,处理完已接受的请求后退出;

    if(cluster.isMaster){
        cluster.fork();
    }else {
        // 出错之后
        try{
            res.end(dddd);  // 报错,整个线程挂掉,不能提供服务,
        }catch(err){
         // 断开连接,断开和Master的连接,守护进程其实就是重启;
            process.disconnect(); // or exit()
        }
    }
进程守护
  • Master进程除了接收新的连接,分发给各worker处理之外,还像天使一样默默守护着这些进程,保障应用的稳定性,一旦某个worker进程退出就fork一个新的子进程顶替上去;

  • 这一切cluster模块已经处理好了,当某个worker进程发生异常退出或者与Master进程失去联系(disconnected)时,master进程都会收到相应的事件通知;

cluster.on('exit',function(){
    cluster.fork();
})

cluster.on('disconnect',function(){
    cluster.fork();
})
IPC通信
  • IPC通信就是进程间的通信;

  • 虽然每个worker进程是相对独立的,但是他们之间还是需要通信的;叫进程间通信(IPC)通信;

  • worker和worker之间的通信通过Master转发:通过worker的pid

const cluster = require('cluster');
if(cluster.isMaster){
    var worker = cluster.fork();
    worker.send('hi, i am master');
    worker.on('message', (msg) =>{
        console.log(`${msg} is from worker ${worker.id}`)   
    })
}else if(cluster.isWorker){
   process.on('message', (msg) =>{
        process.send(msg);
   }) 
}

上述内容就是nodejs中怎么利用cluster实现多进程,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注本站行业资讯频道。

《nodejs中怎么利用cluster实现多进程.doc》

下载本文的Word格式文档,以方便收藏与打印。