nodejs多进程处理方案:pm2中的cluster与fork
Author:zhoulujun Date:
上一篇我们介绍了pm2的使用:《pm2托管npm命令:linux持久运行nodejs npm run服务(开机启动)》,
Node.js中cluster模块
HTTP服务器用于响应来自客户端的请求,当客户端请求数逐渐增大时服务端的处理机制有多种,如tomcat的多线程、nginx的事件循环等。而对于node而言,由于其也采用事件循环和异步I/O机制,因此在高I/O并发的场景下性能非常好,但是由于单个node程序仅仅利用单核cpu,在多核心处理器的系统中并不能发挥其最大的性能。
因此为了更好利用系统资源就需要fork多个node进程执行HTTP服务器逻辑,所以node内建模块提供了child_process和cluster模块。利用child_process模块,我们可以执行shell命令,可以fork子进程执行代码,也可以直接执行二进制文件;利用cluster模块,使用node封装好的API、IPC通道和调度机可以非常简单的创建包括一个master进程下HTTP代理服务器 + 多个worker进程多个HTTP应用服务器的架构,并提供两种调度子进程算法。
关于cluster,参考https://nodejs.org/api/cluster.html
cluster模块如何运作的呢?
首先,Cluster会创建一个master,然后根据你指定的数量复制出多个server app(也被称之为工作线程)。它通过IPC通道与工作线程之间进行通信,并使用内置的负载均衡来更好地处理线程之间的压力,该负载均衡使用了Round-robin算法(也被称之为循环算法)。
cluster用于运行一些可以共享TCP连接的worker进程,首先创建一个master进程,随后根据设置的次数fork出相应的workers,master和workers通过进程间通信(IPC)实现TCP句柄等数据交换,cluster模块自带负载均衡,默认使用Round-Robin算法实现,master监听TCP端口,并根据RR算法将请求交给钦定的worker进行处理。
当使用Round-robin调度策略时,master accepts()所有传入的连接请求,然后将相应的TCP请求处理发送给选中的工作线程(该方式仍然通过IPC来进行通信)。
如何来使用cluster?
const cluster = require('cluster'); const http = require('http'); if (cluster.isMaster) { let numReqs = 0; setInterval(() => { console.log(`numReqs = ${numReqs}`); }, 1000); function messageHandler(msg) { if (msg.cmd && msg.cmd === 'notifyRequest') { numReqs += 1; } } const numCPUs = require('os').cpus().length; for (let i = 0; i < numCPUs; i++) { // 使用 cluster.fork 创建子进程 cluster.fork(); } for (const id in cluster.workers) { cluster.workers[id].on('message', messageHandler); } } else {// Worker processes have a http server. http.Server((req, res) => { res.writeHead(200); res.end('hello world\n'); process.send({ cmd: 'notifyRequest' }); }).listen(8000); }
当然,你可以指定任意数量的工作线程,线程的数量不仅限于CPU核心的数量,因为它只是作为一个运行在CPU上的子线程。
正如你所看到的,要使其正常运行,你需要将你的代码封装到cluster的处理逻辑中,并添加一些额外的代码来指定当一个线程挂掉之后如何进行处理。
PM2内部包含了所有上述的处理逻辑,因此你不必对代码做任何修改。我们将上面的代码还原成最原始的形式:
var http = require('http'); http.createServer(function(req, res) { res.writeHead(200); res.end("hello world"); }).listen(8080);
然后在控制台执行:$ pm2 start app.js -i 4
-i <number of workers>参数用来告诉PM2以cluster_mode的形式运行你的app(对应的叫fork_mode),后面的数字表示要启动的工作线程的数量。如果给定的数字为0,PM2则会根据你CPU核心的数量来生成对应的工作线程。
不论什么情况下,保持你的apps一直运行
如果任意一个工作线程挂掉了,不用担心,PM2会立即将其重启。当然,你也完全可以在任何时候手动重启这些线程
实时扩展集群
任何时候,如果你需要增加工作线程的数量,可以通过pm2 scale <app name> <n>来对集群进行扩展。参数<n>指定工作线程的数量,被用来增加或减少集群数。你也可以通过pm2 scale app +3的方式来指定要增加多少工作线程。
PM2的进程管理模式
Cluster模式和Fork模式是PM2中两种常见的进程管理模式。
Cluster模式
在Cluster模式下,PM2会启动一个主进程和多个工作进程。主进程负责管理和监视工作进程,而工作进程则负责处理实际的请求。这种模式适用于多核CPU服务器,因为它可以利用多个CPU核心并行地处理请求,从而提高应用程序的性能。
要使用Cluster模式,你需要在PM2配置文件中指定instances属性,以指定要启动的工作进程数量。例如,以下是一个使用Cluster模式启动4个工作进程的PM2配置文件:
// pm2.config.js module.exports = { apps: [{ name: 'my-app', script: 'app.js', instances: 4, exec_mode: 'cluster' }] }; };
在上面的示例中,instances属性指定了要启动的工作进程数量,而exec_mode属性指定了使用Cluster模式。
Fork模式
在Fork模式下,PM2会启动多个独立的进程,每个进程都负责处理实际的请求。这种模式适用于单核CPU服务器或者需要使用外部负载均衡器的情况。
要使用Fork模式,你只需要在PM2配置文件中省略instances属性即可。例如,以下是一个使用Fork模式启动的PM2配置文件:
// pm2.config.js module.exports = { apps: [{ name: 'my-app', script: 'app.js', exec_mode: 'fork' }] };
在上面的示例中,exec_mode属性指定了使用Fork模式。
如何选择模式?
择Cluster模式还是Fork模式取决于你的应用程序的特性和需求。如果你的应用程序需要处理大量的并发请求,并且服务器具有多个CPU核心,则应该选择Cluster模式。如果你的应用程序只需要处理少量的并发请求,并且服务器只有一个CPU核心,则应该选择Fork模式。
另外,如果你的应用程序需要使用外部负载均衡器,则也应该选择Fork模式。
参考文章:
https://theanarkh.github.io/understand-nodejs/chapter15-Cluster/
深入浅出 Node.js Cluster https://juejin.cn/post/6844903795252527118
转载本站文章《nodejs多进程处理方案:pm2中的cluster与fork》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/nodejs/8943.html