egg多进程模型注意事项梳理
2020/5/30 5:26:25
本文主要是介绍egg多进程模型注意事项梳理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
背景
最近在项目中使用egg进行服务端开发,在开发过程中遇到了比较诡异的问题,具体表现为mq在监听到信息时,其回调函数会被多次执行,那么这会导致某个文件被同时操作等问题。
问题成因
这边梳理egg文档时,重点过了一下egg多进程的设计模式,了解到egg的master-agent-worker模式,那么这里面有些问题是需要我们在开发时去注意的了。
首先介绍下egg的多进程实现方式
egg通过node提供的cluster实现了多进程模式,为了更好地利用多核环境,egg一般会启用相当于cpu核数的worker,以此来最大化利用cpu能力。
在egg启动时,master,agent,worker的关系如图所示
+---------+ +---------+ +---------+ | Master | | Agent | | Worker | +---------+ +----+----+ +----+----+ | fork agent | | +-------------------->| | | agent ready | | |<--------------------+ | | | fork worker | +----------------------------------------->| | worker ready | | |<-----------------------------------------+ | Egg ready | | +-------------------->| | | Egg ready | | +----------------------------------------->|
在这种模式下,master、agent、worker各司其职,主要制作分配如下:
master:负责维护整个应用稳定性,当有worker因异常而退出时,master负责拉起新的worker,以确保应用正常运行。
agent:由于egg的多进程模型会在每个进程中运行一份我们的应用实例,那么在某些情况下,这种机制会导致问题。比如,保存日志的逻辑如果在每个进程中都执行的话,那么在触发日志保存操作的时候,会有多个进程同时操作日志文件,那么此时就会导致文件读写问题。所以egg设计了agent进程,agent进程只会有一个,不会出现上述问题,这样,对于类似上述的后台运行的逻辑就统一放到agent中去处理了。
worker:负责执行业务代码,处理用户请求和定时任务,egg在框架层保证了定时任务只会在单个worker中执行,所以可以放心使用。
分析egg多进程导致的问题
上面我们分析过了egg的多进程机制,所以我们知道了问题成因,出现我们最开始说的问题的原因是我们把mq的监听和处理逻辑放到了worker中,那么这样的话在实际运行过程中,就会导致mq收到消息时,回调函数被执行多次。
到这里我们已经知道如何优化了,那就是把mq的处理逻辑放到agent中,以确保mq消息的回调仅执行一次。但是细心地你肯定发现了,这里有个问题,agent只有一个实例,如果事情在agent里面做,那么不是无法利用多核性能了吗?
agent与worker通信
的确,我们可以在agent中处理仅需要单次执行的逻辑,但是这样做就没法利用多核性能了。那么有什么办法吗?没错,就是进程间通信,具体思路就是,agent还是负责mq的连接和监听逻辑,但是回调函数不在agent中执行,而是写在worker里面。那么worker什么时候执行这个逻辑呢?答案是,agent通过进程间通信通知worker。egg内部实现了一个进程间通信机制,我们直接调用即可,主要实现方式如下:
广播消息: agent => all workers +--------+ +-------+ | Master |<---------| Agent | +--------+ +-------+ / | \ / | \ / | \ / | \ v v v +----------+ +----------+ +----------+ | Worker 1 | | Worker 2 | | Worker 3 | +----------+ +----------+ +----------+ 指定接收方: one worker => another worker +--------+ +-------+ | Master |----------| Agent | +--------+ +-------+ ^ | send to / | worker 2 / | / | / v +----------+ +----------+ +----------+ | Worker 1 | | Worker 2 | | Worker 3 | +----------+ +----------+ +----------+
这里我们可以看出来,进程间通信都是基于master转发的,所以我们可以利用egg提供的机制,解决我们的问题。
解决办法
如上文分析,我们把mq的连接和监听逻辑放到agent中,当接收到消息时,通过进程间通信把通知发送给worker,然后由worker执行具体的业务逻辑即可。具体代码其实可以参考vue的事件机制,在worker中监听指定事件:
app.messenger.on(action, data => { // 执行业务逻辑 });
在agent中建立mq连接并监听消息,收到消息后触发事件:
exports.task = async ctx => { ...// 收到mq消息的逻辑此处省略 // 准备发送通知 ctx.app.messenger.sendRandom(action); };
注意,需要单次执行的任务要调用sendRandom方法,这个是发送给一个worker的方法。当然,如果要执行多次的,可以调用app.messenger.sendToApp()方法,这个方法会把消息发送给所有worker,并执行多次处理逻辑。
总结
egg在多进程模型中的使用还是需要有一些技巧的,所以需要我们先熟悉egg的多进程机制后再进行业务开发,避免遇到奇怪的坑,浪费时间。
这篇关于egg多进程模型注意事项梳理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南
- 2024-09-30Dnd-Kit学习:新手快速入门指南