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.mzph.cn/news/37675.shtml

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

相关文章

背上小书包准备面试之TypeScript篇

目录 typescript是啥?与javascript的区别? typescript数据类型? typescript中枚举类型?应用场景? typescript中接口的理解?应用场景? typescript中泛型的理解?应用场景&#xf…

轻薄的ESL电子标签有哪些特性?

在智慧物联逐渐走进千万家的当下,技术变革更加日新月异。ESL电子标签作为科技物联的重要组成部分,是推动千行百业数字化转型的重要技术,促进物联网产业的蓬勃发展。在智慧零售、智慧办公、智慧仓储等领域,ESL电子标签在未来是不可…

win11右下角图标(网络,音量,电量)点击无反应问题,两分钟解决!

win11系统用的好好的,突然有一天任务栏右下角的常用三件套(网络,音量,电量)左键单击没反应,无法方便的调节音量和连接wifi,如下图所示,但是右键好用,不过不方便。网上查了…

嵌入式 C 语言程序数据基本存储结构

一、5大内存分区 内存分成5个区,它们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 1、栈区(stack):FIFO就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。 ​…

【Windows API】获取卷标、卷名

1、卷->卷标 使用FindFirstVolume()和FindNextVolume()函数体系,枚举系统所有卷(Volume)的例子,然后获取卷标、卷类型。这个方式可以枚举出没有驱动器号(卷标)的卷。 int TestMode1() {HANDLE hVolume…

Failed to connect to bitbucket.org port 443

浏览器可以访问bitbucket,但是在终端或者sourcetree上死活无法进行pull, push等操作。 Root Cause:“【翻】【墙】软件”使用了http proxy,所以也得为git设置相同的http proxy。 所以,解决方法是: 1,查看“…

网络系统架构演变

1.系统架构演变 随着互联网的发展,网站应用的规模不断扩大。需求的激增,带来的是技术上的压力。系统架构也因此不断的演进、升级、迭代。从单一应用,到垂直拆分,到分布式服务,到SOA,以及现在火热的微服务架…

【Django】无法从“django.utils.encoding”导入名称“force_text”

整晚处理 Django 的导入错误。 我将把它作为提醒,希望处于相同情况的人数会减少。 原因 某些软件包版本不支持Django 4 请看下表并决定Django和Python的版本 方案 如果出现难以响应,或者更改环境麻烦,请尝试以下操作 例如出现以下错误 …

云计算的发展前景怎么样

云计算是当前科技领域中最受关注的领域之一,它的出现改变了传统的计算模式,使得企业和个人能够更加便捷地访问和使用计算资源。随着云计算技术的不断发展,它的前景也变得更加光明。 以下是云计算的发展前景: 云计算的市场份额将继续增长:根据市场研究机构的报告,云计算的市场份…

vfuhyuuy

Sublime Text is an awesome text editor. If you’ve never heard of it, you shouldcheck it out right now. I’ve made this tutorial because there’s no installer for the Linux versions of Sublime Text. While that’s not a real problem, I feel there is a clean…

通过版本号控制强制刷新浏览器或清空浏览器缓存

背景介绍 在我们做 web 项目时,经常会遇到一个问题就是,需要 通知业务人员(系统用户)刷新浏览器或者清空浏览器 cookie 缓存的情况。 而对于用户而言,很多人一方面不懂如何操作,另一方面由于执行力问题&am…

Android descendantFocusability 属性

view 焦点问题处理 作用 通过该属性可以指定viewGroup和其子View到底谁获取焦点, 直接在viewGroup上使用就行。 属性值 属性值含义beforeDescendantsviewgroup会优先其子类控件而获取到焦点afterDescendantsviewgroup只有当其子类控件不需要获取焦点时才获取焦点…

MFC创建和使用OCX控件

文章目录 MFC建立OCX控件注册OCX控件与反注册使用Internet Explorer测试ocx控件OCX控件添加方法OCX控件添加事件Web使用OCX控件MFC使用OCX控件使用OCX控件调用ocx的功能函数对ocx的事件响应OCX控件调试工具tstcon32.exe加载ocx控件使用tstcon32.exe调试ocxMFC建立OCX控件 新建…

【ChatGPT 指令大全】怎么使用ChatGPT来辅助知识学习

目录 概念解说 简易教学 深度教学 教学与测验 解释一个主题的背后原理 总结 在当今信息时代,互联网的快速发展为我们获取知识提供了前所未有的便利。而其中,人工智能技术的应用也为我们的学习和交流带来了新的可能性。作为一种基于自然语言处理的人…

ORA-01704: string literal too long

这是在做数据迁移的时候,将mysql库中的数据整理成Oracle脚本,接着在客户端运行sql脚本插入数据时碰到的问题。明显就是文本太长了导致的报错,但是实际上设置的字段是可以支持这么长的文本数据的。 解决方案 直接写程序导出导入数据&#xff0…

Postgresql 基础使用语法

1.数据类型 1.数字类型 类型 长度 说明 范围 与其他db比较 Smallint 2字节 小范围整数类型 32768到32767 integer 4字节 整数类型 2147483648到2147483647 bigint 8字节 大范围整数类型 -9233203685477808到9223203685477807 decimal 可变 用户指定 精度小…

rust学习-tokio::time

示例 use std::time::Duration; use tokio::{task, time::interval};#[tokio::main] async fn main() {let mut interval interval(Duration::from_secs(1));let handle task::spawn(async move {loop {interval.tick().await;println!("tick");}});handle.await.…

【大数据】一些基本概念

一、数据库、数据仓库、数据湖 1.什么是数据库 (Database, DB) 数据库是指长期储存在计算机中的有组织的, 可共享的数据集合 就是存储数据的仓库 数据库有三个特点: 永久存储, 有组织, 可共享 数据库是一种结构化数据存储技术,用于存储和管理有组织的数据。数据库…

微信小程序云开发快速入门(2/4)

前言 我们对《微信小程序云开发快速入门(1/4)》的知识进行回顾一下。在上章节我们知道了云开发的优势以及能力,并且我们还完成了码仔备忘录的本地版到网络版的改造,主要学习了云数据库同时还通过在小程序使用云API直接操作了云数…

SciencePub学术| 智能计量类重点SCIE征稿中

SciencePub学术 刊源推荐: 智能计量类重点SCIE征稿中!信息如下,录满为止: 一、期刊概况: 智能计量类重点SCIE 【期刊简介】IF:2.0-2.5,JCR3区,中科院4区; 【版面类型】正刊&#…