当前位置:网站首页 > Node.js开发 > 正文

nodejs事件循环与多进程(五)——cluster多进程模型 & worker进程使用fork()函数,实现与master进程间通信 & 惊群之发生多线程多进程等待同一个socket事件

nodejs事件循环与多进程(五)——cluster多进程模型 & worker进程使用fork()函数,实现与master进程间通信 & 惊群之发生多线程/多进程等待同一个socket事件

cluster

node进行多进程的模块

属性和方法

  1. isMaster 属性,返回该进程是不是主进程
  2. isWorker 属性,返回该进程是不是工作进程
  3. fork() 方法,只能通过主进程调用,衍生出一个新的 worker 进程,返回一个 worker 对象。和process.child的区别,不用创建一个新的child.js
  4. setupMaster([settings]) 方法,用于修改 fork() 默认行为,一旦调用,将会按照cluster.settings进行设置。
  5. settings 属性,用于配置,参数 exec: worker文件路径;args: 传递给 worker 的参数;execArgv: 传递给 Node.js 可执行文件的参数列表

事件

  1. fork 事件,当新的工作进程被 fork 时触发,可以用来记录工作进程活动
  2. listening 事件,当一个工作进程调用 listen() 后触发,事件处理器两个参数 worker:工作进程对象
  3. message事件, 比较特殊需要去在单独的worker上监听。
  4. online 事件,复制好一个工作进程后,工作进程主动发送一条 online 消息给主进程,主进程收到消息后触发,回调参数 worker 对象
  5. disconnect 事件,主进程和工作进程之间 IPC 通道断开后触发
  6. exit 事件,有工作进程退出时触发,回调参数 worker 对象、code 退出码、signal 进程被 kill 时的信号
  7. setup 事件,cluster.setupMaster() 执行后触发

文档地址:

https://nodejs.org/api/child_process.html 多看文档!

cluster多进程模型

每个worker进程通过使用child_process.fork()函数,基于IPC(Inter-Process Communication,进程间通信),实现与master进程间通信。

那我们直接用child_process.fork()自己实现不就行了,干嘛需要cluster呢?

这样的方式仅仅实现了多进程。多进程运行还涉及父子进程通信,子进程管理,以及负载均衡等问题,这些特性cluster帮你实现了。 

在这里插入图片描述

实例

文件1

cluster\child.js

console.log('我是子进程') 

文件2

cluster\main.js

var cluster = require('cluster'); var cpuNums = require('os').cpus().length; var http = require('http'); if (cluster.isMaster) { 
    for (var i = 0;i < cpuNums; i++) { 
    cluster.fork('./child.js') } // 当新的工作进程被fork时,cluster模块将触发'fork'事件。 可以被用来记录工作进程活动,产生一个自定义的timeout。 // cluster.on('fork', (worker) => { 
    // console.log('主进程fork了一个worker pid为', worker.process.pid); // }) // 当一个工作进程调用listen()后,工作进程上的server会触发'listening' 事件,同时主进程上的 cluster 也会被触发'listening'事件。 //事件处理器使用两个参数来执行,其中worker包含了工作进程对象, address 包含了以下连接属性: address、 port 和 addressType。当工作进程同时监听多个地址时,这些参数非常有用。 // cluster.on('listening', (worker) => { 
    // console.log('主进程fork了一个worker进行http服务 pid为', worker.process.pid); // }) // 当cluster主进程接收任意工作进程发送的消息后被触发 // cluster.on('message', (data) => { 
    // console.log('收到data', data) // }) // var log = cluster; // Object.keys(cluster.workers).forEach((id) => { 
    // cluster.workers[id].on('message', function(data) {  // console.log(data) // }) // }); cluster.on('disconnect', (worker)=> { 
    console.log('有工作进程退出了', worker.process.pid ) cluster.fork(); // 保证你永远有8个worker }); } else { 
    // http.createServer((req, res) => { 
    // try{ 
    // res.end(aasdasd); // 报错,整个线程挂掉,不能提供服务 // } catch(err) { 
    // process.disconnect(); // 断开连接, 断开和master的连接,守护进程其实就是重启 // } // }).listen(8001, () => { 
    // console.log('server is listening: ' + 8001); // }); // console.log('xxx') process.send(process.pid); // process.disconnect(); } 

打开终端,执行命令

node .\main.js

main文件的console内容都能打印

最初的多进程模型

最初的 Node.js 多进程模型就是这样实现的,master 进程创建 socket,绑定到某个地址以及端口后,自身不调用 listen 来监听连接以及 accept 连接,而是将该 socket 的 fd 传递到 fork 出来的 worker 进程,worker 接收到 fd 后再调用 listen,accept 新的连接。但实际一个新到来的连接最终只能被某一个 worker 进程 accpet 再做处理,至于是哪个 worker 能够 accept 到,开发者完全无法预知以及干预。这势必就导致了当一个新连接到来时,多个 worker 进程会产生竞争,最终由胜出的 worker 获取连接。

在这里插入图片描述

相信到这里大家也应该知道这种多进程模型比较明显的问题了

  • 多个进程之间会竞争 accpet 一个连接,产生惊群现象,效率比较低。
  • 由于无法控制一个新的连接由哪个进程来处理,必然导致各 worker 进程之间的负载非常不均衡。

这其实就是著名的”惊群”现象。

简单说来,多线程/多进程等待同一个 socket 事件,当这个事件发生时,这些线程/进程被同时唤醒,就是惊群。可以想见,效率很低下,许多进程被内核重新调度唤醒,同时去响应这一个事件,当然只有一个进程能处理事件成功,其他的进程在处理该事件失败后重新休眠(也有其他选择)。这种性能浪费现象就是惊群。

惊群通常发生在 server 上,当父进程绑定一个端口监听 socket,然后 fork 出多个子进程,子进程们开始循环处理(比如 accept)这个 socket。每当用户发起一个 TCP 连接时,多个子进程同时被唤醒,然后其中一个子进程 accept 新连接成功,余者皆失败,重新休眠。

http.Server继承了net.Server, http客户端与http服务端的通信均依赖于socket(net.Socket)。

cluster\master.js

const net = require('net'); const fork = require('child_process').fork; var handle = net._createServerHandle('0.0.0.0', 3000); for(var i=0;i<4;i++) { 
    console.log('1111') fork('./worker').send({ 
   }, handle); } 

cluster\worker.js

const net = require('net'); process.on('message', function(m, handle) { 
    //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,handle) { 
    var pid = process.pid; if (!data[pid]) { 
    data[pid] = 0; } data[pid] ++; //每次服务 +1 console.log('got a connection on worker, pid = %d', process.pid, data[pid]); var socket = new net.Socket({ 
    handle: handle }); socket.readable = socket.writable = true; socket.end(res); } } 

打开终端,执行命令

node .\master.js

worker.js文件的console内容都能打印

在这里插入图片描述

到此这篇nodejs事件循环与多进程(五)——cluster多进程模型 & worker进程使用fork()函数,实现与master进程间通信 & 惊群之发生多线程多进程等待同一个socket事件的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • nodejs事件循环与多进程(六)——Nginx是HTTP和反向代理服务器& 正向代理-不知客户端需代理、反向代理-不知服务器需代理& cluster中的优雅退出和进程守护& IPC通信是进程间的通信2024-11-29 16:54:07
  • 将node_modules 文件夹中的所有包打包成压缩包代码实现2024-11-29 16:54:07
  • Baas接口标准(一)——GraphQL介绍、和RESTful对比 & GraphQL客户端与服务端交互(接口调用) & apollo-server框架开发之基于Node.js的GraphQL的开发2024-11-29 16:54:07
  • 2024盘古石取证比赛(手机)2024-11-29 16:54:07
  • 小程序使用node.js开发后台接口_nodejs小程序后端2024-11-29 16:54:07
  • nodejs事件循环与多进程(四)——Process进程-Node全局对象&child_process子进程-exec、execSync、execFile、spawn、fork & Cluster集群2024-11-29 16:54:07
  • nodejs事件循环与多进程(二)——fs和setTimeout、setImmediate关系&事件循环是异步操作&process.nextTick阻塞IO操作&app.on订阅、app.emit触发2024-11-29 16:54:07
  • nodejs事件循环与多进程(一)——事件循环允许Node.js执行非阻塞IO操作 & js是操作DOM,决定了单线程 & 事件循环之宏任务setTimeout在后、微任务promise在前2024-11-29 16:54:07
  • Node.js网络通信(三)——构建http服务之创建http服务、根据url处理响应、响应html内容、处理页面中的静态资源、使用模版引擎& 构建https服务之原理、CA证书、搭建https服务器2024-11-29 16:54:07
  • Node.js 网络通信(二)02-构建UDP服务——UDP简介 & UDP三种传播方式-单播、广播、组播 & UDP一对多通信场景 & dgram模块用于构建UDP服务之Socket方法和事件2024-11-29 16:54:07
  • 全屏图片