Node.js学习笔记-04

这第九章也是个大重点

九、玩转进程

Node在选型时决定在V8引擎之上构建,也就意味着它的模型与浏览器类似。
本章关于进程的介绍和讨论将会解决如下两个问题:

  1. 单进程单线程并非完美,如今CPU基本均是多核的,真正的服务器(非VPS)往往还有多个CPU。——如何充分利用多核CPU服务器?
  2. 由于Node执行在单线程上,一旦单线程上抛出的异常没有捕获,将会引起整个进程的崩溃。——如何保证进程的健壮性和稳定性?

9.1 服务模型的变迁

9.1.1 石器时代:同步

9.1.2 青铜时代:复制进程

9.1.3 白银时代:多进程

9.1.4 黄金时代:事件驱动

9.2 多进程架构

面对单进程单线程对多核使用不足的问题,前人的经验是启动多进程即可。理想状态下每个进程各自利用一个CPU,以此实现多核CPU的利用。
Node提供了 child_process 模块,并且也提供了 child_process.fork()函数实现进程复制。

9.2.1 创建子进程

child_process 模块提供了4个方法用于创建子进程。

spawn(); // 启动一个子进程来执行命令。
exec(); // 启动一个子进程来执行命令,与spawn()不同的是其接口不同,它有一个回调函数获知子进程的状况。
execFile(); // 启动一个子进程来执行可执行文件。
fork(); // 与spawn()类似,不同点在于它创建的Node的子进程只需指定要执行的JavaScript文件模块即可。
  • spawn()、exec()、execFile()不同点:后两者创建时可以指定timeout属性设置超时时间,一旦创建的进程超过设定的时间将会被杀死。
    这里的可执行文件是指可以直接执行的文件,如果是JavaScript文件通过execFile()运行,它的首行内容必须添加如下代码:
#!/usr/bin/env node

尽管4种创建子进程的方式有些差别,但事实上后面三种方法都是spawn()的延伸应用。

9.2.2 进程间的通信

  • 创建子进程后为了实现父子进程之间的通信,父与子之间会创建IPC通道,通过IPC通道父子进程之间才能通过messagesend()传递消息。

  • IPC(Inter-Process Communication)进程间的通信。实现进程间通信的技术也有很多,如:命名管道、匿名管道、socket、信号量、共享内存、消息队列、Domain Socket等。Node中实现IPC通道的是管道(pipe)技术。在Node中管道只是个抽象层面的称呼,具体实现由 libuv 提供,在Windows下有命名管道(named pipe)实现,*nix系统则采用Unix Domain Socket实现,表现在应用层上的进程间通信只有简单的 message 事件和 send() 方法。

  • 与网络socket的行为比较类似,属于双向通信。不同的是他们在系统内核中就完成了进程间的通信,而不用经过实际的网络层,非常高效。

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

9.2.3 句柄传递

send(message, [sendHandle])方法除了能通过IPC发送数据外,还能发送句柄,第二个可选参数就是句柄。
什么是句柄?一种可以用来标识资源的引用,它的内部包含了指向对象的文件描述符。比如句柄可以用来标识一个服务器端socket对象、一个客户端socket对象、一个UDP套接字、一个管道等。P252

发送句柄意味着什么?在前一个问题中,我们可以去掉代理这种方案,使主进程接收到 socket 请求后,将这个socket直接发送给工作进程,而不是重新与工作进程之间建立新的socket连接来转发数据。文件描述符浪费的问题可以通过这样的方式轻松解决。P253

1、句柄发送与还原
2、端口共同监听

9.2.4 小结

至此,我们介绍了创建子进程、进程间通信的IPC通道实现、句柄在进程间的发送和还原、端口共用等细节。通过这些基础技术,用child_process模块在单机上搭建Node集群是件相当容易的事情。因此在多核CPU的环境下让Node进程能够充分利用资源不再是难题。

9.3 集群稳定之路

  • 性能问题。
  • 多个工作进程的存活状态管理。
  • 工作进程的平滑重启。
  • 配置或者静态数据的动态重新载入。
  • 其他细节。

9.3.1 进程事件 P258

9.3.2 自动重启 P259

9.3.3 负载均衡 P264

9.3.4 状态共享 P265

9.4 Cluster 模块

前文介绍了child process模块中的大多数细节,以及如何通过这个模块构建强大的单机集群。如果熟知Node,也许你会惊讶为何迟迟不谈cluster模块。上述提及的问题,Node在v0.8版本时新增的cluster模块就能解决。在v0.8版本之前,实现多进程架构必须通过child process来实现,要创建单机Node集群,由于有这么多细节需要处理,对普通工程师而言是一件相对较难的工作,于是v0.8时直接引入了cluter模块,用以解决多核CPU的利用率问题,同时也提供了较完善的API,用以处理进程的健壮性问题。
P267

9.4.1 Cluster 工作原理

事实上cluster模块就是child process和net模块的组合应用。cluster启动时,如同我们在9.2.3节里的代码一样,它会在内部启动TCP服务器,在cluster.fork()子进程时,将这个TCP服务器端socket的文件描述符发送给工作进程。如果进程是通过cluster.fork()复制出来的,那么它的环境变量里就存在NODE_UNIOUE_ID如果作进中存在listen()侦听网络端口的调用,它将拿到该文件描述符,通过SO_REUSEADDR端口重用,从而实现多个子进程共享端口。对于普通方式启动的进程,则不存在文件描述符传递共享等事情。
在cluster内部隐式创建TCP服务器的方式对使用者来说十分透明,但也正是这种方式使得它无法如直接使用child_process那样灵活。在cluster模块应用中,一个主进程只能管理一组工作进程,如下图所示。( 书中P268)
在cluster模块应用中,一个主进程只能管理一组工作进程
对于自行通过child process来操作时,则可以更灵活地控制工作进程,甚至控制多组工作进程。其原因在于自行通过child process操作子进程时,可以隐式地创建多个TCP服务器使得子进程可以共享多个的服务器端socket。

9.4.2 Cluster 事件

对于健壮性处理,cluster模块也暴露了相当多的事件。

  • fork:复制一个工作进程后触发该事件。
  • online:复制好一个工作进程后,工作进程主动发送一条nline消息给主进程,主进程收到消息后,触发该事件。
  • listening:工作进程中调用listen()(共享了服务器端Socket)后,发送一条listening消息给主进程,主进程收到消息后,触发该事件。
  • disconnect:主进程和工作进程之间IPC通道断开后会触发该事件。
  • exit:有工作进程退出时触发该事件。
  • setup:cluster.setupMaster()执行后触发该事件。

这些事件大多跟child process模块的事件相关,在进程间消息传递的基础上完成的封装这些事件对于增强应用的健壮性已经足够了。

9.5 总结

尽管Node从单线程的角度来讲它有够脆弱的:既不能充分利用多核CPU资源,稳定性也无法得到保障。但是群体的力量是强大的,通过简单的主从模式,就可以将应用的质量提升一个档次。在实际的复杂业务中,我们可能要启动很多子进程来处理任务,结构甚至远比主从模式复杂,但是每个子进程应当是简单到只做好一件事,然后通过进程间通信技术将它们连接起来即可。这符合Unix的设计理念,每个进程只做一件事,并做好一件事,将复杂分解为简单,将简单组合成强大。
尽管通过child_process模块可以大幅提升Node的稳定性,但是一旦主进程出现问题所有子进程将会失去管理。在Node的进程管理之外,还需要用监听进程数量或监听日志的方式确保整个系统的稳定性,即使主进程出错退出,也能及时得到监控警报,使得开发者可以及时处理故障。

个人心得:这章学得我脑壳痛,下次再重新学一遍然。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/89387.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 8 group by 报错 this is incompatible with sql_mode=only_full_group_by

文章目录 sql_mode配置ONLY_FULL_GROUP_BYSTRICT_TRANS_TABLESNO_ZERO_IN_DATENO_ZERO_DATEERROR_FOR_DIVISION_BY_ZERONO_AUTO_CREATE_USERNO_ENGINE_SUBSTITUTION 局部修改配置windows修改配置Linux修改配置 sql_mode配置 ONLY_FULL_GROUP_BY 用于控制是否允许对查询结果进…

springboot汽车租赁后台java出租客户管理jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 springboot汽车租赁后台 系统有1权限:管理…

mysql索引的数据结构(Innodb)

首选要注意,这里的数据结构是存储在硬盘上的数据结构,不是内存中的数据结构,要重点考虑io次数. 一.不适合的数据结构: 1.Hash:不适合进行范围查询和模糊匹配查询.(有些数据库索引会使用Hash,但是只能精准匹配) 2.红黑树:可以范围查询和模糊匹配,但是和硬盘io次数比较多. 二…

NLP文本匹配任务Text Matching [有监督训练]:PointWise(单塔)、DSSM(双塔)、Sentence BERT(双塔)项目实践

NLP文本匹配任务Text Matching [有监督训练]:PointWise(单塔)、DSSM(双塔)、Sentence BERT(双塔)项目实践 0 背景介绍以及相关概念 本项目对3种常用的文本匹配的方法进行实现:Poin…

【闲侃历史】 唐朝----安史之乱那些事(1)

说到安史之乱,可谓是唐朝最乱的一段时期,据说唐朝当时也就5000多万人,而经历了这一战,人口只剩1000多万人了。著名的杨国忠和杨贵妃也是在这个时候死的。这个系列我们就先来侃侃发起安史之乱的两个人----安禄山和史思明 一. 安禄…

Django的简介安装与配置及两大设计模式

一.Djang的介绍 1.Django是什么 Django 是使用 Python 语言开发的一款免费而且开源的 Web 应用框架。 由于 Python 语言的跨平台性,所以 Django 同样支持 Windows、Linux 和 Mac 系统。 在 Python 语言炽手可热的当下,Django 也迅速的崛起,在…

LeetCode150道面试经典题-- 有效的字母异位词(简单)

1.题目 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 2.示例 s"adasd" t"daads" 返回true s"addad" t &q…

最小生成树(Kruskal)克鲁斯卡尔算法

算法步骤总共分为两步,由并查集实现 第一步(把所有的边按边长的大小进行排序) 第二步(如果两个点不连通就把两点之间的边加上再把两个点连通) 当放入的边数为点数减去一时就代表已经全部连通 例题一(859. …

[Mongodb 5.0]聚合操作

本文对应Aggregation Operations — MongoDB Manual 正文 此章节主要介绍了Aggregation Pipeline,其实就是将若干个聚合操作放在管道中进行执行,每一个聚合操作的结果作为下一个聚合操作的输入,每个聚合指令被称为一个stage。 在正式开始学…

电压放大器和电荷放大器区别是什么意思

电压放大器和电荷放大器是两种常见的信号放大器。它们的区别主要在于其输入端口所呈现的电路特性不同。 电压放大器的介绍 电压放大器是一种将输入信号的电压增益放大的电路元件,其输入端口呈现高阻抗特性。即在输入端口上,电压放大器所对应的电路模型中…

探索数据之美:初步学习 Python 柱状图绘制

文章目录 一 基础柱状图1.1 创建简单柱状图1.2 反转x和y轴1.3 数值标签在右侧1.4 演示结果 二 基础时间线柱状图2.1 创建时间线2.2 时间线主题设置取值表2.3 演示结果 三 GDP动态柱状图绘制3.1 需求分析3.2 数据文件内容3.3 列表排序方法3.4 参考代码3.5 运行结果 一 基础柱状图…

【Android】MVC,MVP,MVVM三种架构模式的区别

MVC 传统的代码架构模式,仅仅是对代码进行了分层,其中的C代表Controller,控制的意思 将代码划分为数据层,视图层,控制层,三层之间可以任意交互 MVP MVP是在MVC基础上改进而来的一种架构,其中的…

微信开发之一键退出群聊的技术实现

简要描述: 退出群聊 请求URL: http://域名地址/quitChatRoom 请求方式: POST 请求头Headers: Content-Type:application/jsonAuthorization:login接口返回 参数: 参数名必选类型说明wI…

0基础学C#笔记09:希尔排序法

文章目录 前言一、希尔排序的思想二、使用步骤总结 前言 希尔排序可以说是插入排序的一种变种。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它…

React源码解析18(3)------ beginWork的工作流程【mount】

摘要 OK,经过上一篇文章。我们调用了: const root document.querySelector(#root); ReactDOM.createRoot(root)生成了FilberRootNode和HostRootFilber。 并且二者之间的对应关系也已经确定。 而下一步我们就需要调用render方法来讲react元素挂载在ro…

gitee分支合并

合并dev分支到master(合并到主分支) git checkout master git merge dev //这里的dev表示你的分支名称 git push //推送到远程仓库 效果如下图 不报错就表示推送成功了,希望能帮助各位小伙伴

设计模式之七:适配器模式与外观模式

面向对象适配器将一个接口转换成另一个接口,以符合客户的期望。 // 用火鸡来冒充一下鸭子class Duck { public:virtual void quack() 0;virtual void fly() 0; };class Turkey { public:virtual void gobble() 0;virtual void fly() 0; };class TurkeyAdapter :…

SpringBean的生命周期和循环依赖

Spring循环依赖 前言 大制作来啦,spring源码篇,很早之前我就想写一系列spring源码篇了,正好最近总是下雨,不想出门,那就让我来带大家走进Spring源码世界吧。 阅读建议 spring源码读起来有点难度,需要多Deb…

学习笔记-JVM-工具包(JVM分析工具)

常用工具 JDK工具 ① jps: JVM Process status tool:JVM进程状态工具,查看进程基本信息 ② jstat: JVM statistics monitoring tool : JVM统计监控工具,查看堆,GC详细信息 ③ jinfo:Java Configuration I…

Mysql 和Oracle的区别

、mysql与oracle都是关系型数据库,Oracle是大型数据库,而MySQL是中小型数据库。但是MySQL是开源的,但是Oracle是收费的,而且比较贵。 1 2 mysql默认端口:3306,默认用户:root oracle默认端口&…