如何理解node的多进程

2020-09-09  本文已影响0人  jluemmmm

事件驱动

nodejs基于chrome v8引擎构建,默认单线程单进程模式,nodejs的单线程指的是js引擎只有一个实例,且是在主线程执行的(减少线程间切换的开销,不用考虑锁和线程池问题),其他的异步IO和事件驱动相关的线程通过libuv实现内部的线程池和线程调度。libuv存在一个事件循环,事件循环中维持一个执行栈和任务队列,在执行栈中,如果有异步IO及定时器等函数的话,就把异步回调函数放入事件队列中,执行栈执行完成后,从事件队列中按照一定的顺序执行事件队列中的异步回调。

模块调用

nodejs中的模块调用,js代码调用c++核心模块,核心模块调用内建模块,通过libuv进行系统调用,送入线程池等待执行。线程池中的I/O操作调用完成之后会保存结果向IOCP(一种高性能的I/O模型,一种应用程序使用线程池处理异步I/O请求的机制)提交执行状态告知当前对象操作完成并将线程归还线程池

非阻塞I/O

程序执行过程中需要进行很多I/O操作,读写文件、输入输出、请求响应等,I/O操作较为费时,基于node的事件循环机制,在I/O操作的同时,可以继续执行其他的代码。如文件IO,nodejs调用libuv后,libuv在其他线程执行I/O任务,线程完成任务后会通知主线程,主线程回调nodejs。

多进程

nodejs以单线程模式运行,使用事件驱动处理并发,可以在多核CPU系统上创建多个子线程。进程分为master进程和worker进程,master进程负责调度和管理worker进程,worker进程负责具体的业务处理,在服务器层面,worker是一个服务进程,负责处理来自客户端的请求,多个worker相当于多个服务器,因此构成一个服务器群,master进程负责创建worker,接收客户端的请求,分配到各服务器上去处理,监控worker的运行状态及管理操作。

node提供child_process模块创建子进程。nodejs实现多进程

  • spawn 使用指定的命令行参数创建新进程
  • fork 用于在子进程中运行的模块,基于spawn的封装,fork('./main.js)相当于spawn('node', ['./main.js']),fork会在父进程与子进程之间,建立一个用于通信的管道,用于进程间的通信
  • exec 使用子进程执行命令,缓存子进程的输出,将子进程的输出以回调函数参数的形式返回。execFile基于spawn封装,可以直接创建子进程进行文件操作,exec基于execFile封装,可以直接开启子进程执行命令,常见的应用场景如http-server以及webpack-dev-server命令行在启动本地服务是自动打开浏览器。

浅谈NodeJS多进程服务架构基本原理

集群与进程通信

node主进程在创建子进程的时候吧把主进程正在监听的server当作参数传给子进程,子进程自己也创建一个server来监听主进程传来的server。通过process.on中的message接受信息,使用process.send发送信息。

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);
});

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

cluster 模块可以创建共享服务器端口的子进程。

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);
}

模块分类

nodejs如何和libuv和v8一起合作

nodejs深入系列文章

Node.js运行原理、高并发性能测试对比及生态圈汇总

上一篇下一篇

猜你喜欢

热点阅读