前言

JavaScript 主线程运行在单个进程的单个线程上。这样做的好处是:

  • 程序状态是单一的,在没有多线程的情况下没有锁、线程同步问题,
  • 操作系统在调度时因为较少上下文的切换,可以很好地提高CPU的使用率。

但是单进程单线程并非完美的结构,一旦线程中某段代码发生异常阻塞,会阻塞代码执行而浪费资源。同时,如今CPU基本均是多核的,服务器往往还有多个CPU。

因此 Nodejs 不可避免的面临两个问题:如何充分利用多核CPU ****和 ****如何保证进程的健壮性和稳定性 。 另外,由于 Nodejs 中所有处理都在单线程上进行,影响事件驱动服务模型性能的点在于CPU的计算能力,而不受多进程或多线程模式中资源上限的影响,可伸缩性远比前两者高。如果解决掉多核CPU的利用问题,带来的性能上提升是可观的。

进程的创建和使用

多核利用率

面对单进程单线程对多核使用不足的问题,最简单的方法是启动多进程即可。理想状态下每个进程各自利用一个CPU,以此实现多核CPU的利用。Nodejs 提供了 child_process模块,并且也提供了child_process.fork() 方法帮助我们实现进程的复制。

你可以通过这个方法在本地启动多个 HTTP 服务,首先编写一段创建 http服务端 的代码:

const http = require("http");
const server = http.createServer((req, res) => {
  res.writeHead(200, {
    "Content-Type": "text/plain"
  });
  res.end("hello,world!");
});
// 随机监听1000-1999的任意一个端口
server.listen(Math.floor((1   Math.random()) * 1000));

然后创建一个主进程 master.js 来启动和管理他们:

const fork = require("child_process").fork;
const cpus = require("os").cpus();
console.log(cpus.length);
for (let i = 0; i < cpus.length; i  ) {
  fork('./server.js');
}

💡 在 Linux 系统中,你可以通过 ps aux | grep worker.js 来直接查看,在 Windows 中,你能通过 netstat -a 然后查看 1000-1999 端口的进程。

这样的模式称为 Master-Worker模式,又称 主从模式。如图,进程分为两种:主进程和工作进程。这是典型的分布式架构中用于并行处理业务的模式,具备较好的可伸缩性和稳定性:

  • 主进程不负责具体的业务处理,而是负责调度或管理工作进程,它是趋向于稳定的。
  • 工作进程负责具体的业务处理,趋于不稳定。

💡 fork() 能让我们复制进程使每个CPU内核都使用上,但是依然要切记 fork() 进程是昂贵的。因为Node通过事件驱动和异步IO的方式很大的缓解了并发问题,所以这里启动多个进程只是为了充分将CPU资源利用起来,而不是为了解决并发问题。

创建子进程

child_process模块 给予 Node 可以随意创建子进程(child_process)的能力。它提供了4个方法用于创建子进程:

  • spawn():启动一个子进程来执行命令。
  • exec():启动一个子进程来执行命令。与spawn()不同的是其接口不同,它有一个回调函数获知子进程的状况。
  • execFile():启动一个子进程来执行可执行文件。
  • fork():与 spawn() 类似,不同点在于它创建 Node 的子进程只需指定要执行的 JavaScript 文件模块即可。
const cp = require("child_process");
cp.spawn("node", ["./server.js"]);
cp.exec("node server.js", (err, stdout, stderr) => {
  // TODO
});
cp.execFile("server.js", (err, stdout, stderr) => {
  // TODO
});
cp.fork('./server.js');

💡 execFile() 只能用于可以直接执行的文件。在 Linux 中,你可以在文件开头加入 #! /usr/bin/env node

进程间通信 IPC

Master-Worker模式 中,要实现主进程管理和调度工作进程的功能,需要主进程和工作进程之间的通信。子进程对象则由 send() 方法实现主进程向子进程发送数据,message事件 实现收听子进程发来的数据:

// parent.js
const cp = require("child_process");
const n = cp.fork("./child.js");
n.on('message', (msg) => {
  console.log('parent got msg: ', msg);
});
n.send({
  s: 'hello, world',
});
// child.js
process.on('message', (msg) => {
  console.log('child got msg', msg);
});
process.send({
  b: 'bar',
});

💡 HTML5提出了 WebWorker API 来创建工作线程,而主进程和工作进程之间通过 onmessage()postMessage() 进行通信。具体参考MDN文档。

通过 fork() 或者其他API,创建子进程之后,为了实现父子进程之间的通信,父进程与子进程之间将会创建IPC通道(Inter-Process Communication,即进程间通信) 。通过IPC通道,父子进程之间才能通过message和send()传递消息。

父进程在实际创建子进程之前,会创建IPC通道并监听它,然后才真正创建出子进程,并通过环境变量(NODE_CHANNEL_FD)告诉子进程这个IPC通道的文件描述符。子进程在启动的过程中,根据文件描述符去连接这个已存在的IPC通道,从而完成父子进程之间的连接。

💡 只有启动的子进程是Node进程时,子进程才会根据环境变量去连接IPC通道。对于其他类型的子进程则无法实现进程间通信,除非其他进程也按约定去连接这个已经创建好的IPC通道

总结

今天我们讨论了 Nodejs 在多核利用方法的问题,然后介绍了创建子进程、进程间通信与IPC通道的内容。通过这些基础技术,用 child_process模块 在单机上搭建 Nodejs集群 是件相对容易的事情,让 Nodejs 能够在多核CPU的环境下充分利用计算资源。

以上就是详解如何利用Nodejs构建多进程应用的详细内容,更多关于Nodejs构建多进程应用的资料请关注Devmax其它相关文章!

详解如何利用Nodejs构建多进程应用的更多相关文章

  1. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  2. 浅析Nodejs npm常用命令

    这篇文章主要介绍了浅析Nodejs npm常用命令的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

  3. nodejs 使用nodejs-websocket模块实现点对点实时通讯

    这篇文章主要介绍了nodejs 使用nodejs-websocket模块实现点对点实时通讯的实例代码,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  4. nodeJs链接Mysql做增删改查的简单操作

    本篇文章主要介绍了nodeJs链接Mysql做增删改查的简单操作,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. Nodejs中使用captchapng模块生成图片验证码

    本篇文章主要介绍了Nodejs中使用captchapng模块实现图片验证码,非常具有实用价值,需要的朋友可以参考下

  6. nodejs 图片预览和上传的示例代码

    本篇文章主要介绍了nodejs 图片预览和上传的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. nodejs中函数的调用实例详解

    本文通过实例代码给大家介绍了nodejs函数的调用,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  8. NodeJS使用formidable实现文件上传

    这篇文章主要为大家详细介绍了NodeJS使用formidable实现文件上传的相关方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Nodejs获取网络数据并生成Excel表格

    这篇文章主要为大家详细介绍了Nodejs获取网络数据并生成Excel表格的具体实现方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. NodeJS实现不可逆加密与密码密文保存的方法

    这篇文章主要介绍了NodeJS实现不可逆加密与密码密文保存的方法,简单讲述了不可逆加密与密码密文保存的原理并结合实例形式分析了nodejs相关加密操作实现技巧,需要的朋友可以参考下

随机推荐

  1. Error: Cannot find module ‘node:util‘问题解决

    控制台 安装 Vue-Cli 最后一步出现 Error: Cannot find module 'node:util' 问题解决方案1.问题C:\Windows\System32>cnpm install -g @vue/cli@4.0.3internal/modules/cjs/loader.js:638 throw err; &nbs

  2. yarn的安装和使用(全网最详细)

    一、yarn的简介:Yarn是facebook发布的一款取代npm的包管理工具。二、yarn的特点:速度超快。Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。超级安全。在执行代码之前,Yarn 会通过算法校验每个安装包的完整性。超级可靠。使用详细、简洁的锁文件格式和明确的安装算法,Yarn 能够保证在不同系统上无差异的工作。三、y

  3. 前端环境 本机可切换node多版本 问题源头是node使用的高版本

    前言投降投降 重头再来 重装环境 也就分分钟的事 偏要折腾 这下好了1天了 还没折腾出来问题的源头是node 使用的高版本 方案那就用 本机可切换多版本最终问题是因为nodejs的版本太高,导致的node-sass不兼容问题,我的node是v16.14.0的版本,项目中用了"node-sass": "^4.7.2"版本,无法匹配当前的node版本根据文章的提

  4. nodejs模块学习之connect解析

    这篇文章主要介绍了nodejs模块学习之connect解析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. nodejs npm package.json中文文档

    这篇文章主要介绍了nodejs npm package.json中文文档,本文档中描述的很多行为都受npm-config(7)的影响,需要的朋友可以参考下

  6. 详解koa2学习中使用 async 、await、promise解决异步的问题

    这篇文章主要介绍了详解koa2学习中使用 async 、await、promise解决异步的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. Node.js编写爬虫的基本思路及抓取百度图片的实例分享

    这篇文章主要介绍了Node.js编写爬虫的基本思路及抓取百度图片的实例分享,其中作者提到了需要特别注意GBK转码的转码问题,需要的朋友可以参考下

  8. CentOS 8.2服务器上安装最新版Node.js的方法

    这篇文章主要介绍了CentOS 8.2服务器上安装最新版Node.js的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  9. node.js三个步骤实现一个服务器及Express包使用

    这篇文章主要介绍了node.js三个步骤实现一个服务器及Express包使用,文章通过新建一个文件展开全文内容,具有一定的参考价值,需要的小伙伴可以参考一下

  10. node下使用UglifyJS压缩合并JS文件的方法

    下面小编就为大家分享一篇node下使用UglifyJS压缩合并JS文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

返回
顶部