当前位置: 首页 > 后端技术 > Node.js

nodejs中创建集群

时间:2023-04-03 19:41:28 Node.js

简介在上一篇文章中,我们提到可以通过worker_threads创建新的线程,使用child_process可以创建新的子进程。本文将介绍如何创建nodejs集群。Clustercluster我们知道nodejs的事件循环或者事件响应处理器是单线程的,但是现在的CPU基本都是多核的。为了充分利用现代CPU的多核特性,我们可以创建集群,让多个子进程共享同一个服务器端口。也就是说,通过集群,我们可以使用多个子进程来服务同一个端口的请求。先看一个简单的http服务器使用cluster的例子:constcluster=require('cluster');consthttp=require('http');constnumCPUs=require('os').cpus().length;if(cluster.isMaster){console.log(`主进程${process.pid}正在运行`);//生成工作进程。for(leti=0;i{console.log(`workerprocess${worker.process.pid}exited`);});}else{//worker进程可以共享任何TCP连接。//在这个例子中,HTTP服务器是共享的。http.createServer((req,res)=>{res.writeHead(200);res.end('Helloworld\n');}).listen(8000);console.log(`workerprocess${process.pid}started`);}cluster详解cluster模块来源于lib/cluster.js,我们可以使用cluster.fork()创建子worker进程来处理主进程的请求。集群中的eventcluster继承自events.EventEmitter,因此集群可以发送和接收事件。集群支持7个事件,分别是disconnect、exit、fork、listening、message、online和setup。在讲解disconnect之前,我们先介绍一个概念,叫做IPC。IPC的全称是Inter-ProcessCommunication,即进程间通信。IPC主要用于主进程和子进程之间的通信。工作进程在创建时会自动附加到其主进程。只有在触发“断开连接”事件时才会断开连接。触发断开连接的原因有很多。可以是worker.disconnect()的主动调用,也可以是worker进程退出或被杀死。cluster.on('disconnect',(worker)=>{console.log(`工作进程#${worker.id}已断开连接`);});退出事件将在任何工作进程关闭时触发。一般用于监控集群中某个进程是否异常退出。如果退出,使用cluster.fork创建一个新的进程,保证有足够的进程来处理请求。cluster.on('exit',(worker,code,signal)=>{console.log('Workerprocess%dclosed(%s).Restarting...',worker.process.pid,signal||code);cluster.fork();});当调用cluster.fork方法时会触发fork事件。consttimeouts=[];functionerrorMsg(){console.error('connectionerror');}cluster.on('fork',(worker)=>{timeouts[worker.id]=setTimeout(errorMsg,2000);});当worker进程调用listen方法时,主进程和worker进程的监听事件都会被触发。cluster.on('listening',(worker,address)=>{console.log(`worker进程连接到${address.address}:${address.port}`);});其中worker代表Worker线程,address包含三个属性:address、port和addressType。addressType有四个可选值:4(TCPv4)6(TCPv6)-1(Unixdomainsocket)'udp4'or'udp6'(UDPv4orv6)message事件会接收主进程中子进程发送的消息处理时间触发。fork在主进程产生一个worker进程时触发,online在worker进程运行时触发。当调用setupMaster方法时,会触发setup事件。集群中的方法集群中有3个方法,分别是disconnect、fork和setupMaster。cluster.disconnect([callback])调用的是集群的disconnect方法,实际上是调用集群中每个worker中的disconnect方法。从而断开工作人员与主进程的连接。当所有worker都断开连接时,将执行回调。cluster.fork([env])fork方法将从主进程创建一个新的子进程。其中env是要添加到流程环境变量的键值对。fork将返回一个代表工作进程的cluster.Worker对象。最后一个方法是setupMaster:cluster.setupMaster([settings])默认情况下,集群使用fork方法创建子进程,但是我们可以通过setupMaster改变这种行为。通过设置settings变量,我们可以改变后续fork子进程的行为。我们来看一个setupMaster的例子:constcluster=require('cluster');cluster.setupMaster({exec:'worker.js',args:['--use','https'],silent:true});集群.fork();//https工作进程cluster.setupMaster({exec:'worker.js',args:['--use','http']});集群.fork();//httpwork进程cluster中的属性通过cluster对象传递,我们可以通过isMaster和isWorker判断进程是否是master进程。可以通过worker获取当前worker进程对象的引用:constcluster=require('cluster');if(cluster.isMaster){console.log('Thisisthemasterprocess');集群.fork();cluster.fork();}elseif(cluster.isWorker){console.log(`Thisistheworkerprocess#${cluster.worker.id}`);}通过workers可以遍历活跃的worker进程对象://遍历所有worker进程。functioneachWorker(callback){for(constidincluster.workers){callback(cluster.workers[id]);}}eachWorker((worker)=>{worker.send('通知所有worker进程');});每个worker都有一个id号,用于定位worker。集群中的workerworker类包含了worker进程的所有公共信息和方法。cluster.fork出来的是worker对象。Worker事件类似于集群事件,支持6种事件:disconnect、error、exit、listening、message和online。worker包含3个属性,分别是:id、process和exitedAfterDisconnect。其中id是工作人员的唯一标签。worker中的进程实际上是一个ChildProcess对象,由child_process.fork()创建。因为process在worker中是一个全局变量,所以我们可以直接在worker中使用process来发送消息。如果工作进程由于.kill()或.disconnect()退出,则exitedAfterDisconnect为真。如果以其他方式退出,则返回值为false。如果工作进程尚未退出则未定义。我们可以通过worker.exitedAfterDisconnect来区分是主动退出还是被动退出。主进程可以根据这个值决定是否重新生成worker进程。cluster.on('exit',(worker,code,signal)=>{if(worker.exitedAfterDisconnect===true){console.log('这是自发退出,别担心');}});//杀死工作进程。工人.kill();worker还支持6个方法,分别是:send、kill、destroy、disconnect、isConnected、isDead。这里主要讲解发送消息的send方法:worker.send(message[,sendHandle[,options]][,callback])可以看到send方法和child_process中的send方法参数其实很相似。虽然本质上worker.send在主进程中,但它会向特定的工作进程发送消息。相当于ChildProcess.send()。在工作进程中,这会将消息发送到主进程。相当于process.send()。如果(cluster.isMaster){constworker=cluster.fork();worker.send('Hello');}elseif(cluster.isWorker){process.on('message',(msg)=>{process.send(msg);});}在上面的例子中,如果你在主进程中,可以使用worker.send发送消息。在子进程中,可以使用worker中的全局变量process发送消息。总结一下集群的使用,充分利用多核CPU的优势,希望大家在实际项目中应用。本文作者:flydean程序那些事本文链接:http://www.flydean.com/nodejs-cluster/本文来源:flydean的博客欢迎关注我的公众号:《程序与事》最通俗的解读,最深刻的干货,最简洁的教程,还有很多你不知道的小技巧等你来发现!