NodeJS是基于chrome浏览器的V8引擎构建的,也就说明它的模型与浏览器是类似的。我们的javascript会运行在单个进程的单个线程上。这样有一个好处:

  • 状态单一

  • 没有锁

  • 不需要线程间同步

  • 减少系统上下文的切换

  • 有效提高单核CPU的使用率

但是V8引擎的单进程单线程并不是完美的结构,现如今CPU基本上都是多核的。真正的服务器往往有好几个CPU(像我们的线上物理机有12个核),所以,这就将抛出NodeJS实际应用中的第一个问题:“如何充分利用多核CPU服务器?”

另外,由于Node执行在单线程上,一旦单线程出现未捕获的异常,就会造成这个进程crash。所以就遇到了第二个问题:“如何保证进程的健壮性和稳定性?”

从严格意义上来讲,Node其实并不是真正的单线程架构,因为Node自身还有I/O线程存在(网络I/O、磁盘I/O),这些I/O线程是由更底层的libuv处理,这部分线程对于JavaScript开发者来说是透明的。JavaScript代码永远运行在V8上,是单线程的。所以表面上来看NodeJS是单线程的。

服务器进程模型的进化

1、同步单进程服务器

这类服务器是最早出现的,其执行模型是同步的(基于read或select I/O模型),它的服务模式是一次只能处理一个请求,其他的请求都需要按照顺序依次等待接受处理。这就意味着除了当前的请求被处理之外,剩下的请求都是处于阻塞等待的状态。所以,它的处理能力特别的低下。
假如服务器每次响应请求处理的时间为N秒,那么这类服务器的QPS为1/N

2、同步多进程服务器

为了解决上面的同步单进程服务器无法处理的并发问题,这类服务器通过进程的复制同时服务更多的请求和用户。一个请求需要一个进程来服务,也就是100个请求就需要100个进程来进行服务,这需要很大的代价。因为在进程的复制总会复制进程内部的状态,对于每个连接都进行这样的复制的话,相同的状态会在内存中存在很多份,造成浪费。同时这个过程会因为复制很多个进程影响进行的启动时间。而且服务器的进程数量也是有上限的。所以,这个模型并没有实质上解决并发问题。
假如这类服务器的进程数上限为M,每个请求处理的时间为N秒,那么这类服务器的QPS为M*1/N

3、同步多进程多线程服务器

为了解决进程复制中的资源浪费问题,多线程被引入了服务模型,从一个进程处理一个请求改为一个线程处理一个请求。线程相对于进程的开销要小许多,而且线程之间可以共享数据。此外可以利用线程池来减少创建和销毁线程的开销。但是多线程所面临的并发问题只能说比多进程好点而已,因为每个线程需要一定内存来存放自己的堆栈。另外一个CPU核心只能处理一件事,系统是通过将CPU切分为时间片的方法来让线程可以均匀地使用CPU资源,在系统切换线程的过程中也会进行线程的上下文切换(切换为当前线程的堆栈),当线程数量过多时进行上下文切换会非常耗费时间。所以在大的并发量下,多线程结构还是无法做到强大的伸缩性。大名鼎鼎的Apache服务器就是采用了这样的架构,所以出现了著名的C10K问题。
我们忽略系统进行线程的上下文切换的开销,假如这类服务器可以创建M个进程,一个进程可以使用L个线程,每个请求处理的时间为N秒,那么它的QPS为M*L/N

4、单进程单线程下基于事件驱动的服务器

为了解决C10K以及解决更高并发的问题,基于epoll(效率最高的I/O事件通知机制)的事件驱动模型出现了。采用单线程避免了不必要的内存开销和上下文切换开销。
不过这种基于事件的服务器模型存在的文章刚开始提出两个问题:“CPU的利用率和健壮性”。

另外,所有的请求处理都在单线程上进行,影响事件驱动服务模型性能的只有CPU的计算能力,它的上限决定了这类服务器的性能上限,但它不受多进程多线程模式中资源上限的影响,可伸缩性比前两者都高。如果可以解决多核CPU的利用问题,那么带来的性能提升是非常高的。

NodeJS的多进程架构

面对单进程单线程对多核使用率不高的问题,按照之前的经验,每个进程各使用一个CPU即可,以此实现多核CPU的利用。Node提供了child_process模块,并且也提供了fork()方法来实现进程的复制(只要是进程复制,都需要一定的资源和时间。Node复制进程需要不小于10M的内存和不小于30ms的时间)。

这样的解决方案就是*nix系统上最经典的Master-Worker模式,又称为主从模式。这种典型并行处理业务模式的分布式架构具备较好的可伸缩性(可伸缩性实际上是和并行算法以及并行计算机体系结构放在一起讨论的。某个算法在某个机器上的可扩放性反映该算法是否能有效利用不断增加的CPU。)和稳定性。主进程不负责具体的业务处理,而是负责调度和管理工作进程,工作进程负责具体的业务处理,所以,工作进程的稳定性是开发人员需要关注的。

通过fork()复制的进程都是一个独立的进程,这个进程中有着独立而全新的V8实例。虽然Node提供了fork()用来复制进程使每个CPU内核都使用上,但是依然要记住fork()进程代价是很大的。好在Node通过事件驱动在单个线程上可以处理大并发的请求。

注意:这里启动多个进程只是为了充分将CPU资源利用起来,而不是为了解决并发问题。

Node创建子进程的4种方式

1、spawn()

创建一个子进程来执行命令

2、exec()

创建一个子进程来执行命令,和spawn()不同的是方法参数不同,它可以传入回调函数来获取子进程的状态

3、execFile()

启动一个子进程来执行指定文件。注意,该文件的顶部必须声明SHEBANG符号(#!)用来指定进程类型。

4、fork()

和spawn()类似,不同点在于它创建Node的子进程只需要执定要执行的JavaScript文件模块即可。

注意:后面的3种方法都是spawn()的延伸应用。

Node进程间通信

Master-Worker模式中,要实现主进程管理和调度工作进程的功能,需要主进程和工作进程之间的通信。它们通过消息来传递内容,而不是共享文件或直接操作相关资源,这是比较轻量和无依赖的做法。

通过fork()或者其他的API创建子进程之后,为了实现父子进程之间的通信,父进程与子进程之间将会创建IPC通道。通过IPC通道,父子进程之间才可以传递消息。

IPC(进程间通信)原理

IPC全称 Inter-Process Communication,也就是进程间通信。进程间通信的目的是为了让不同的进程能够互相访问资源并进行协调工作。Node中的IPC创建和实现过程如下:

父进程在实际创建子进程之前,会先创建IPC通道并监听它,然后才真正创建出子进程。子进程在启动的过程中会去链接这个已存在的IPC通道,从而完成了父子进程之间的连接。

句柄传递

创建好进程之间的IPC之后,如果仅仅只用来发送一些简单数据,显然不够我们的实际使用。
理想情况下,不管服务启动了多少个进程都应该经过同一个Master进程来进行控制和调度。所以所有请求都应该先经过同一个端口,然后通过Master进程交由具体的Worker进程处理。

代理模式

让每个进程监听不同的端口,其中主进程监听主端口(80端口),主进程对外接受所有的网络请求,再将这些请求代理到不同的端口进程上。

通过代理,可以避免端口不能重复监听的问题,也可以在代理进程做适当的负载均衡,这样每个子进程都可以均衡的处理服务。

由于进程每接受到一个连接,将会用到一个文件描述符,因此代理模式连接工作进程的过程需要用到两个文件描述符。操作系统的文件描述符是有限的。所以这种方案影响了系统的扩展能力

句柄共享模式

Nodejs提供了进程间发送句柄的功能。有了这个功能我们可以不使用代理模式方案,使主进程接受到socket请求之后,将这个socket对象直接转发给工作进程,而不是重新遇工作进程之间创建新的socket连接来转发数据。这样的话,文件描述符浪费的问题可以轻轻松解决。

在程序设计中,句柄(handle)是一种特殊的智能指针。当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄。

这样所有的请求都是由子进程处理了。整个过程中,服务的过程发生了一次改变如下图:

主进程发送完句柄并关闭监听之后,就成了下图的机构。

多个应用监听相同的端口时,文件描述符同一时间只能被某个进程所用,也就是网络请求发送的服务器端时,只有一个幸运的进程能够抢到连接,只有它能为这个请求进行服务。所以这些进程服务是抢占式的。

至此,以此介绍了创建子进程、进程间通信的IPC通道实现、句柄在进程间的发送和使用原理、端口共用等细节。通过这些基础技术,在多核的CPU服务器上,让Node进程能够充分利用资源不是难题。

Node服务稳定性

搭建好了集群,充分利用了多核CPU的资源,但是在迎接大量的客户端请求之前,还有很多稳定性的问题亟待解决。

  • 工作进程存活状态管理

  • 工作进程平滑重启

  • 工作进程限量重启

  • 工作进程性能问题

  • 工作进程负载均衡

  • 工作进程状态共享

原文 https://segmentfault.com/a/1190000007343993

NodeJS充分利用多核CPU以及它的稳定性相关推荐

  1. nodejs 获取cpu核心数量_用 NodeJS 充分利用多核 CPU 的资源[每日前端夜话0xCB]

    每日前端夜话0xCA 每日前端夜话,陪你聊前端. 每天晚上18:00准时推送. 正文共:1558 字 预计阅读时间:7 分钟 作者:Nick Major 翻译:疯狂的技术宅 来源:coderrocke ...

  2. NodeJS应用部署之PM2(充分利用多核cpu)

    前言 正文 推荐资料 附录:NodeJS学习网络资料整理 1 从零开始 – 入门篇 2 成为高手 – 进阶篇 3 追根溯源 – 内核篇 4 跨界应用 – 创造篇 5 利剑在手 – 工具篇 6 Web技 ...

  3. python多线程不能利用多核cpu,但有时候多线程确实比单线程快。

    python 为什么不能利用多核 CPU  GIL 其实是因为在 python中有一个 GIL( Global Interpreter Lock),中文为:全局解释器锁.  1.最开始时候设计GIL是 ...

  4. 程序 多核优化 linux,linux 多核CPU性能调优

    常常感觉系统资源不够用,一台机子上跑了不下3个比较重要的服务,但是每天我们还要在上面进行个备份压缩等处理,网络长时间传输,这在就很影响本就不够用的系统资源: 这个时候我们就可以把一些不太重要的比如co ...

  5. 服务器多个cpu的作用,服务器多核CPU是什么?多核CPU有什么用?

    服务器多核CPU是什么?多核CPU有什么用?许多人到购买服务器的情况下都是在网络服务器的配备中见到CPU一栏时会写着2核.四核.八核乃至十六核的字眼,那麼这种"核"是什么呢?她们与 ...

  6. php-fpm 多核,linux 多核CPU性能调优

    常常感觉系统资源不够用,一台机子上跑了不下3个比较重要的服务,但是每天我们还要在上面进行个备份压缩等处理,网络长时间传输,这在就很影响本就不够用的系统资源: 这个时候我们就可以把一些不太重要的比如co ...

  7. Node.js 能否充分利用多核处理器?

    (默认的)Node.js 应用程序总是单线程的模型,即使在多核处理器上运行,应用程序也能只使用一个处理器. 但是 Node.js 的核心模块之一 Cluster 支持 Node.js 应用程序开启多核 ...

  8. 如何利用多核CPU提高虚拟现实性能?

    虚拟现实引领新时代令人惊喜的新体验,但也带来了各种新的挑战.其中之一就是虚拟现实应用"耗能"问题. 虚拟现实挑战了图形和仿真技术,以至于创造优秀虚拟现实体验的硬件需求成为日前热点. ...

  9. 多核CPU上python多线程并行的一个假象(转)

    转自:http://www.cnblogs.com/skying555/p/6527189.html GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么 ...

最新文章

  1. python学习教程,猜数字游戏开发
  2. c# GDI+画折线图(初级版本)
  3. Bash字符串处理(与Java对照) - 19.查找字符的位置
  4. c++中map的基本函数
  5. 数组 -- 3Sum Closet -- 图解
  6. php 重定义数组k,PHP基础篇之数组
  7. 2016 hack.lu-ctf redacted RSA数据恢复
  8. Ubuntu 16.04下使用Wine安装Windows版的微信(不太完美)
  9. 颜色恒常性 传统算法(AWB)
  10. ppt给图片增加高斯模糊_PPT图片处理小技巧
  11. 【蓝桥杯】最长子序列
  12. 如何在微信读书上阅读极客时间专栏?
  13. Navicat导出数据库表
  14. 计算机p是什么单位是什么,功率的计算公式及单位
  15. 此实现不是 Windows 平台 FIPS 验证的加密算法的一部分解决办法
  16. 用事实说话,成熟的ORM性能不是瓶颈,灵活性不是问题:EF5.0、PDF.NET5.0、Dapper原理分析与测试手记(转)...
  17. Linux socket accept尽信书不如无书
  18. 国开计算机网络 形考4,国开电大计算机网络(本)形考作业四参考答
  19. labview 和lin 通讯_LABVIEW几种通讯应用1
  20. Java 并发编程(二)对象的发布逸出和线程封闭

热门文章

  1. 手写实现一个HashMap
  2. 阿里国际站用户增长技术探索与实践
  3. 乱七八糟之处理器天梯图
  4. HTML和CSS实现京东首页(html和css详解)
  5. 搭建类京东网站服务器
  6. 【报告分享】2021返乡置业报告-贝壳研究院(附下载)
  7. 电脑上怎么绘制流程图?三分钟快速绘制流程图的秘诀
  8. lol服务器维护8月7,LOL8月7日更新维护到几点 英雄联盟8.7更新了哪些内容
  9. Baumer工业相机堡盟工业相机如何通过BGAPISDK显示彩色相机和黑白相机的图像(C#)
  10. MATLAB 自然数e的表达式坑、如何求解含有未知量的行列式