« 给 skynet 添加 mongo driver | 返回首页 | 读了一点 go 的源码 »

如何安全的退出 skynet

Skynet 在最开始设计的时候是没有仔细考虑系统退出的问题的,后来为了检测内存泄露的问题,加入了一个 ABORT 指令可以杀掉全部活着的服务。

安全的退出整个系统,尤其是一个分布式系统,总是一个复杂的问题。我们的内部版为这些做了大量的工作。但我觉得做的不太干净,所以一直没有把代码合并到开源版。

今天晓靖又重提这个退出系统的方案,就又把这个问题拿出来讨论了一下。我的个人观点是,如何安全的退出和业务逻辑相关性很强,在框架中加入大量的通知机制让每个服务自己协调解决即增加了框架的复杂度,又不降低系统的设计难度。我们目前内部版本中增加的服务退出消息以及服务优先级等等这些机构过于复杂,且没有很好的解决问题。

曾经我想过按操作系统的做法,杀掉一个服务先发送一个消息给这个服务,让服务有一小段时间可以做最好的事务处理。等超时后,就强行把服务杀掉。这样显得不够安全,但若等服务自行干净退出又有可能发生死锁。我觉得,对于整个系统都是自己设计构建的话,其实设计人员是能够理解如何安全的关闭系统的。只有小部分服务需要做善后工作,比如数据库读写层需要把尚未写完的数据写入数据库后才能退出;大部分服务是无状态的,它们可以直接清理;还有一部分服务的关闭过程比较复杂,比如网关,就需要先关闭监听端口,再逐个关闭客户链接,最后才能退出自己。

让每个服务自己收到退出消息后想办法处理好退出流程,不如有一个专门掌管系统关闭的服务来统一协调系统关闭退出的流程。目前的 launcher 服务掌管了大部分服务的启动流程,可以稍加改进来管理退出过程。也可以把这一部分业务独立实现。无论怎样,都不要在框架底层来做太多事情。每个有复杂退出流程的服务,应在启动时把自己上报,退出管理器了解所有系统中活跃的服务,按系统的整体设计来决定退出的时候按怎样的次序做好哪些事情。

框架可以做一点点事情,能让这件事情做起来简洁一点。那就是可以指定一个服务可以监听到其它服务的关闭事件,而不需要服务在退出的时候自行汇报。

我没有在框架层把这个服务退出机制设计成 Erlang 那样的 process link 的方式是因为,n:m 的 process link 会使得管理连接的模块实现的过于复杂。用单点接收所有的服务退出消息,同样也可以在这个单点上进一步实现出 Erlang 那样的 process link 机制来。


目前的接口是放在 skynet.lua 里的 skynet.monitor 方法。在启动脚本里调用它启动一个监听服务。我编写了一个简单的监听服务 simplemonitor.lua ,在每个服务退出时输出一行 log 。用户可以改进这个服务做更多的事情。

Comments

Cloud大神,评论的循序要是反过来就好了
RSS 一直是全文的, blog 有两个源, 另一个是 atom 的. 见源代码.
交给运维手动来搞吧。 PS:请问能不能把RSS设置为输出全文?
Skynet 是个什么?能否讲个概况?架构呢?
程序设计最核心的地方是运行中的状态,最繁琐复杂的地方是初始化,最蛋疼的是退出清理。框架是为逻辑服务的,框架的目的是减少逻辑的工作量。
对网络游戏来说,状态基本上都在每个客户端的session中,只要前端代理服务逐个把客户端关闭掉,让状态按照正常的客户端关闭流程来保存,等到所有的客户端都关闭了,那么整个服务就可以安全的自行关闭,直接杀进程都是没问题的。
我听说Erlang的退出机制是“Let it crash”,我觉得你们可以用C语言和Lua模仿一下(不怀好意的笑了)。

Post a comment

非这个主题相关的留言请到:留言本