egg.js 基础概念

一、应用、框架、插件

1、一个应用必须指定一个框架才能运行起来。
2、根据需要可以给一个应用配置多个不同的插件。
3、框架是一个启动器,必须有它才能运行起来。框架还是一个封装器,它可以在已有框架的基础上进行封装,框架也可以配置插件,其中 Egg,EggCore 都是框架。
4、插件只完成特定独立的功能,实现即插即拔的效果

二、egg-cluster

1、NodeJs 中 javascript 的执行是单线程的,所以一个进程只能使用一个 CPU
2、可以利用 Node 自带 child_process 和 cluster 模块可以方便实现多进程之间的通信
3、egg-cluster 是 Egg 的多进程模型的启动模式,在使用 cluster 模式启动 Egg 应用时,我们只需要配置相关启动参数, egg-cluster 会自动创建相关进程,并管理各个进程之间的通信以及异常处理等问题。
主进程 Master 通过 child_process 模块的 fork 函数创建 Agent 子进程,并通过 cluster 模块创建 Worker 子进程。
4、Master 进程只有一个且第一个启动,主要负责进程管理的工作,包括 Worker、Agent 进程的初始化和重启以及进程之间的通信工作(负责 agent 和各个 worker 之间的通信。负责各个 worker 之间的通信)。


egg.js 基础概念_第1张图片
Egg 多进程模型

Master 不运行任何业务代码,它的稳定性特别重要,一旦挂掉整个 Node 服务就挂掉了。
5、Agent 进程也只有一个,一般在业务开发时我们不太会用到 Agent 进程,主要处理公共资源的访问,如文件监听,或者帮 worker 处理一些公共事务,如一些事情是不需要每个 worker 都做一次的,agent 帮忙做完之后通知它们执行之后的操作。
6、Worker 进程根据用户自己的设定可以有多个,主要负责处理业务逻辑和用户的请求。当 Worker 进程异常退出时,Master 进程会重启一个新的 Worker 进程。
一般是根据服务器有多少个 CPU 启动多少个这样的 worker 进程。
7、Agent 子进程是 Egg.Agent 类的实例,Worker 子进程是 Egg.Application 的实例,而 Egg.Agent 和 Egg.Application 都是 EggApplication 的子类,而 EggApplication 类又是 EggCore 的子类


egg.js 基础概念_第2张图片
类与实例之间的关系图

8、各进程的启动顺序
egg.js 基础概念_第3张图片
image.png

a. master 启动后先启动 agent 进程
b. agent 初始化成功后,通过 IPC 通道通知 master
c. master 根据 CPU 的个数启动相同数目的 worker 进程
d. worker 进程初始化成功后,通过 IPC 通道通知 master

e. 所有的进程初始化成功后,master 通知 agent 和各个 worker 进程应用启动成功

启动方式差异:
master 启动 agent 和 worker 的方式明显不一样,启动 agent 使用的是 child_process 的 fork 模式,启动各个 worker 使用的是 cluster 的 fork 模式,为什么不能都使用同一种方式来启动?因为它们所负责处理的事情性质是不一样的,agent 是类似于作为各个 worker 秘书的存在,只负责帮它们处理轻量级的服务,是不直接对外提供 http 访问的,所以 master 用 cluster.fork 把各个 worker 启动起来,并提供对外 http 访问,这些 worker 在 cluster 的预处理下能够对同一端口进行监听而不会产生端口冲突,同时使用 round-robin 策略进行负载均衡把收到的 http 请求合理地分配给各个 worker 进行处理

三、进程间通信

master 和 agent/worker 是 real communication,
agent 和 worker 之间以及各个 worker 之间是 virtual communication
每个 Worker 进程是相对独立的,但是它们之间始终还是需要通讯的,叫进程间通讯(IPC)。


egg.js 基础概念_第4张图片
image.png

1、master 继承了 events 模块,拥有 events 监听、发送消息的能力,master 进程自身是通过订阅者模式来进行事务处理的,所以在 master 的源码里面并没有看到过多的 callback hell
2、master 是 agent 的父进程,相互可以通过 IPC 通道进行通信
3、master 是 worker 的父进程,相互可以通过 IPC 通道进行通信
4、agent 和各个 worker 之间毕竟是不同进程,是无法直接进行通信的,所以需要借助master 的力量进行转发,egg-cluster 封装了一个 messenger 的工具类,对各个进程间消息转发进行了封装
5、各个 worker 之间由于是不同进程,也是无法直接进行通信的,需要借助 master 的力量进行转发,原理同上

6、各进程的状态通知:
a. worker 启动成功后 master 会对其状态进行监听,可以第一时间感知到失联的 worker,在这情况下 master 会对这些 worker 之前所绑定的事件进行销毁防止内存泄露,并且通知 agent,最后 refork 出同等数量的 worker 保证业务的顺利进行,对 worker 的 fork 和 refork 操作都是通过工具类 cfork 进行的
b. agent 启动成功后 master 会对其状态进行监听,对于退出或者失联的 agent master 是清楚的,在这情况下 master 会对这些 agent 之前所绑定的事件进行销毁防止内存泄露,并且通知各个 worker,最后重启 agent 进程保证业务的顺利进行
c. master 退出了或者失联了,cluster 会这样处理:当父进程退出后子进程自动退出
d. master 退出了或者失联了,agent 也像 worker 一样退出吗?然而并不是!这是child_process.fork 和 cluster.fork 的不同之处,master 退出了或者失联了,agent 进程还继续运行,但是它的父进程已经不在了,它将会被 init 进程收养,从而成为孤儿进程,当这样的孤儿进程越来越多的时候服务器就会越来越卡。所以 master 退出后需要指定 agent 也一起退出!

参考文档:
https://juejin.im/entry/59bcce1b5188257e82676b53
https://zhuanlan.zhihu.com/p/49276061
https://eggjs.org/zh-cn/core/cluster-and-ipc.html

你可能感兴趣的:(egg.js 基础概念)