nodejs cluster模块初探

大家都知道nodejs是一个单进程单线程的服务器引擎,不管有多么的强大硬件,只能利用到单个CPU进行计算。所以,为了使用多核cpu来提高性能 就有了cluster,让node可以利用多核CPU实现并行。

随着nodejs的发展,让nodejs上生产环境,就必须是支持多进程多核处理!在V0.6.0版本,Nodejs内置了cluster的特性。自此,Nodejs终于可以作为一个独立的应用开发解决方案,映入大家眼帘了。

这个包不用安装,node默认自带。

引入cluster

1

const cluster = require('cluster');

  

如果你有多进程使用的经验,就一定知道一般来说很多多进程的模型都是 一个主进程,然后fork一堆工作进程。我们这里也不例外。 下面看一个简单的例子。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

const cluster = require('cluster');

const http = require('http');

const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {

for (var i = 0; i < numCPUs; i++) {

cluster.fork();

}

cluster.on('exit', (worker, code, signal) => {

console.log(`worker ${worker.process.pid} died`);

});

else {

http.createServer((req, res) => {

res.writeHead(200);

res.end('hello world\n');

}).listen(8000);

}

  


这个demo首先引入了 cluster 然后判断是否是主进程,如果是的话 进入主进程 创建 cpu个数 个子进程。然后监听子进程exit

子进程if判断未通过,所以进入else 执行创建http代码

这样就可以简单的实现了一个单机多进程的httpd服务器。

#### 初窥
nodejs把进程封装的很全面,所以以前有c基础的同学再看node就会感觉非常简单。大家都知道在c里面 我们是通过fork的返回值判断到底是主进程还是子进程 那么在node里面 isMaster 到底是何方神圣呢。

其实node会在子进程里面添加一个环境变量

1

2

3

module.exports = ('NODE_UNIQUE_ID' in process.env) ?

require('internal/cluster/child') :

require('internal/cluster/master');

  

只需要判断当前进程有没有环境变量“NODE_UNIQUE_ID”就可知道当前进程是否是主进程;而变量“NODE_UNIQUE_ID”则是在主进程fork子进程时传递进去的参数,因此采用cluster.fork创建的子进程是一定包含“NODE_UNIQUE_ID”的。

消息通信


nodejs为我们屏蔽了底层的多进程信息通信,提供了一个 `send` 和 `on` 事件来传递消息,不过只能子进程和父进程传递,如果我们要2个子进程传递的话必须通过主进程做中转。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

const cluster = require('cluster');

const http = require('http');

const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {

for (var i = 0; i < numCPUs; i++) {

var worker = cluster.fork();

(function (i) {

workers[i].on('message'function(message) {

if (message.cmd == 'start') {

console.log(JSON.stringify(message));

}

});

workers[i].send({cmd:'callback',msg:"收到收到"});

})(i);

}

cluster.on('exit', (worker, code, signal) => {

console.log(`worker ${worker.process.pid} died`);

});

else {

http.createServer((req, res) => {

res.writeHead(200);

res.end('hello world\n');

process.send({cmd: 'start',msg:"我已准备好!"});

}).listen(8000);

}

  


上面代码我们通过 子进程 `process.send` 发送给父进程,然后父进程接收到消息后 通过`send`回传的一个简单demo。

疑惑,多个子进程可以监听一个端口吗?

 

大家看到上面的几个例子,都是多个子进程监听同一个8000端口,那么有同学会有疑问,多个socket是否可以同时监听一个端口呢.

其实 cluster 实现同时多个进程监听一个端口,有两种方法。


 1、 RoundRobin 默认*


主进程每fork一个子进程,都会调用handoff函数,进入该子进程的处理循环中。一旦主进程没有缓存的客户端请求时(this.handles为空),便会将当前子进程加入free空闲队列,等待主进程的下一步调度。这就是cluster模式的RoundRobin调度策略,每个子进程的处理逻辑都是一个闭环,直到主进程缓存的客户端请求处理完毕时,该子进程的处理闭环才被打开。在这个模式中,其实子进程 listen是个假的,并不会真正的监听端口,而是主进程来监听端口,如果有请求过来,就会调用其中的一个子进程来处理。

 


2、shared socket (windows默认)


shared socket策略(后文简称SS策略)采用SS策略调度算法,子进程的服务器工作逻辑完全不同于上文中所讲的那样,子进程创建的TCP服务器会在底层侦听端口并处理响应,这是如何实现的呢?SS策略的核心在于IPC传输句柄的文件描述符,并且在C++层设置端口的**SO_REUSEADDR(端口复用)** 选项,最后根据传输的文件描述符还原出handle(net.TCP),处理请求。这正是shared socket名称由来,共享文件描述符。

既然SS策略传递的是master进程的服务端socket的文件描述符,子进程侦听该描述符,那么由谁来调度哪个子进程处理请求呢?这就是由操作系统内核来进行调度。可是内核调度往往出现意想不到的效果,在linux下导致请求往往集中在某几个子进程中处理。这从内核的调度策略也可以推算一二,内核的进程调度离不开上下文切换,上下文切换的代价很高,不仅需要保存当前进程的代码、数据和堆栈等用户空间数据,还需要保存各种寄存器,如PC,ESP,最后还需要恢复被调度进程的上下文状态,仍然包括代码、数据和各种寄存器,因此代价非常大。而linux内核在调度这些子进程时往往倾向于唤醒最近被阻塞的子进程,上下文切换的代价相对较小。而且内核的调度策略往往受到当前系统的运行任务数量和资源使用情况,对专注于业务开发的http服务器影响较大,因此会造成某些子进程的负载严重不均衡的状况。那么为什么cluster模块默认会在windows机器中采用SS策略调度子进程呢?原因是node在windows平台采用的IOCP来最大化性能,它使得传递连接的句柄到其他进程的成本很高,因此采用默认的依靠操作系统调度的SS策略。


今天就大概写到这里,其实我对cluster了解的也不算很多,这篇文章就当是个抛砖引玉吧。欢迎大家一起来共同学习。

cluster 常用对象

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

cluster的各种属性和函数

cluster.setttings:配置集群参数对象

cluster.isMaster:判断是不是master节点

cluster.isWorker:判断是不是worker节点

Event: 'fork': 监听创建worker进程事件

Event: 'online': 监听worker创建成功事件

Event: 'listening': 监听worker向master状态事件

Event: 'disconnect': 监听worker断线事件

Event: 'exit': 监听worker退出事件

Event: 'setup': 监听setupMaster事件

cluster.setupMaster([settings]) : 设置集群参数

cluster.fork([env]): 创建worker进程

cluster.disconnect([callback]): 关闭worket进程

cluster.worker: 获得当前的worker对象

cluster.workers: 获得集群中所有存活的worker对象

worker对象

worker的各种属性和函数:可以通过cluster.workers, cluster.worket获得。

worker.id: 进程ID号

worker.process: ChildProcess对象

worker.suicide: 在disconnect()后,判断worker是否自杀

worker.send(message, [sendHandle]): master给worker发送消息。注:worker给发master发送消息要用process.send(message)

worker.kill([signal='SIGTERM']): 杀死指定的worker,别名destory()

worker.disconnect(): 断开worker连接,让worker自杀

Event: 'message': 监听master和worker的message事件

Event: 'online': 监听指定的worker创建成功事件

Event: 'listening': 监听master向worker状态事件

Event: 'disconnect': 监听worker断线事件

Event: 'exit': 监听worker退出事件

  

参考文档
 Nodejs cluster模块深入探究
https://cnodejs.org/topic/596ffb9b3f0ab31540ed4b91
官方文档
https://nodejs.org/api/cluster.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Springboot+Vue的智慧养老服务管理系统源码+项目使用说明(优秀毕业设计).zip 该项目属于个人毕业设计,经导师的精心指导与严格评审获得高分通过的设计项目。主要针对计算机相关专业的教师、正在做毕设、课设的学生使用,也可作为项目实战演练,可直接作为课程设计、期末大作业、毕设等。 1.项目代码功能经验证ok,确保稳定可靠运行。欢迎下载使用!在使用过程中,如有问题或建议,请及时私信沟通。 2.主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 介绍 随着人口老龄化趋势的加剧,老年人口比例不断增加,传统的养老服务模式已经难以满足现代老年人的多元化需求。因此,如何高效、精准地提供养老服务,成为了社会关注的焦点。信息化与智能化的发展为养老服务带来了新的机遇。智慧养老作为新兴的养老服务模式,正逐步改变传统的养老服务格局。 #### 安装教程 1. 运行环境准备mysql8+java8+npm14.16.1 2. 配置maven路径,加载依赖 3. 运行sql文件,确保application.yml的数据库名称和账号密码是数据库所在主机的账号密码 #### 使用说明 1. 登入 账号:admin 密码:admin 账号:user 密码:123456 2.运行流程 前端初始化指令: > npm install 前端运行指令(有两个端,一个是管理端,一个是用户端): > npm run serve #### 项目演示 + 普通用户 访问者可以在最顶端看到系统的导航栏,根据自己的需求点击需要去到的页面。用户可以单击“入院指南”,在入院指南界面的输入框中输入标题并进行搜索,就可以查看标题、发布时间、注意事项、发布人、封面等其他信息,在个人中心界面中,可以看见家属的账号、密码和性别等基本信息,还可以对这些信息进行更新操作。 ![GIF 2024-6-17 19-49-40](GIF 2024-6-17 19-49-40-1718630421956.gif) + 管理员 管理员单击家属管理,在家属管理页面中输入家属的各项信息后,在页面中进行查询、新增或删除家属信息等操作。管理员点击护工管理,在护工管理页面中输入护工的所有信息,然后在页面上可以点击详情来查看护工的详细情况,点击修改来修改护工的信息,点击删除来删除护工的信息。管理员单击房间资料管理,在这个页面中可以对房间资料的信息进行管理。管理员单击床位管理,可以查看房间号、楼房名称等各项信息,还可以点击修改来修改床位信息,点击删除来删除床位信息。管理员还可以对老人入住进行管理,在这个界面中可以查看像入住编号、老人年龄等老人入住的详细信息,可以在界面顶端输入具体信息来查找,还可以点击删除来进行删除操作。管理员单击外出报备管理,在外出报备管理界面中可以查看老人的外出报备情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值