深入理解NodeJS 多进程和集群(4)

exec 与 execFile 的区别在于传参,execFile 第一个参数为文件的可执行路径或命令,第二个参数为命令的参数集合(数组),第三个参数为 options,最后一个参数为回调函数,回调函数的形参为错误、标准输出和错误输出。

exec 在传参上将 execFile 的前两个参数进行了整合,也就是命令与命令参数拼接成字符串作为第一参数,后面的参数都与 execFile 相同。

cluster 集群

开启进程需要消耗内存,所以开启进程的数量要适合,合理运用多进程可以大大提高效率,如 Webpack 对资源进行打包,就开启了多个进程同时进行,大大提高了打包速度,集群也是多进程重要的应用之一,用多个进程同时监听同一个服务,一般开启进程的数量跟 CPU 核数相同为好,此时多个进程监听的服务会根据请求压力分流处理,也可以通过设置每个子进程处理请求的数量来实现 “负载均衡”。

1、使用 ipc 实现集群

ipc 标准进程通信使用 send 方法发送消息时第二个参数支持传入一个服务,必须是 http 服务或者 tcp 服务,子进程通过 message 事件进行接收,回调的参数分别对应发送的参数,即第一个参数为消息,第二个参数为服务,我们就可以在子进程创建服务并对主进程的服务进行监听和操作(listen 除了可以监听端口号也可以监听服务),便实现了集群,代码如下。

// 文件:server.js const os = require("os"); // os 模块用于获取系统信息 const http = require("http"); const path = require("path"); const { fork } = rquire("child_process"); // 创建服务 const server = createServer((res, req) => { res.end("hello"); }).listen(3000); // 根据 CPU 个数创建子进程 os.cpus().forEach(() => { fork("child_server.js", { cwd: path.join(__dirname); }).send("server", server); });

// 文件:child_server.js const http = require("http"); // 接收来自主进程发来的服务 process.on("message", (data, server) => { http.createServer((req, res) => { res.end(`child${process.pid}`); }).listen(server); // 子进程共用主进程的服务 });

上面代码中由主进程处理的请求会返回 hello,由子进程处理的请求会返回 child 加进程的 pid 组成的字符串。

2、使用 cluster 实现集群

cluster 模块是 NodeJS 提供的用来实现集群的,他将 child_process 创建子进程的方法集成进去,实现方式要比使用 ipc 更简洁。

// 文件:cluster.js const cluster = require("cluster"); const http = require("http"); const os = require("os"); // 判断当前执行的进程是否为主进程,为主进程则创建子进程,否则用子进程监听服务 if (cluster.isMaster) { // 创建子进程 os.cpus().forEach(() => cluster.fork()); } else { // 创建并监听服务 http.createServer((req, res) => { res.end(`child${process.pid}`); }).listen(3000); }

上面代码既会执行 if 又会执行 else,这看似很奇怪,但其实不是在同一次执行的,主进程执行时会通过 cluster.fork 创建子进程,当子进程被创建会将该文件再次执行,此时则会执行 else 中对服务的监听,还有另一种用法将主进程和子进程执行的代码拆分开,逻辑更清晰,用法如下。

// 文件:cluster.js const cluster = require("cluster"); const path = require("path"); const os = require("os"); // 设置子进程读取文件的路径 cluster.setupMaster({ exec: path.join(__dirname, "cluster-server.js") }); // 创建子进程 os.cpus().forEach(() => cluster.fork());

// 文件:cluster-server.js const http = require("http"); // 创建并监听服务 http.createServer((req, res) => { res.end(`child${process.pid}`); }).listen(3000);

通过 cluster.setupMaster 设置子进程执行文件以后,就可以将主进程和子进程的逻辑拆分开,在实际的开发中这样的方式也是最常用的,耦合度低,可读性好,更符合开发的原则。

总结

本篇着重的介绍了 NodeJS 多进程的实现方式以及集群的使用,之所以在开头长篇大论的介绍 spawn,是因为其他的所有跟多进程相关的方法包括 fork、exec 等,以及模块 cluster 都是基于 spawn 的封装,如果对 spawn 足够了解,其他的也不在话下,希望大家通过这篇可以在 NodeJS 多进程相关的开发中起到一个 “路标” 的作用。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/f85f11545a6d699f3769ace80be336ea.html