Monibuca v5 实现热重启
优雅关闭
在 v4 中关闭一个流通过改变流的生命周期实现
v4 中流有一个 G(goroutine)专门负责管理流的生命周期,并使用状态自动机来实现状态变更。
但是在退出发布者或者订阅者,仍然遇到一些问题,首先发布者和订阅者各自有自己的 G ,多数用于网络通讯。此外退出分为两种情况,一种是内部原因,比如超时,出错等。另一种是外部原因,比如用户手动关闭,连接断开等。很难优雅的统一处理。
v5 中通过第一性原理思考,移除不必要的 G,不再有管理生命周期的状态机,流和发布者变成同一个概念,实现主动被动退出的统一处理,使得代码进一步简化。
优雅关闭流和订阅者
为了尽量减少锁和 G 的使用,因此选择使用动态 Select 方式,在 Server 层面的一个大 G 中实现,对发布者和订阅者的退出监听。下面是伪代码,为了方便理解
为啥优雅呢?因为在一个 G 里面处理,不需要锁,可以方便的修改发布者集合,订阅者集合,以及等待区(订阅时还没有发布者)等很多并发读写的场景。实际上你无法直接写出这个 select,因为发布者和订阅者动态添加和删除的。此时就需要用到 reflect.Select(cases)
了。
优雅关闭 Server
有了优雅关闭发布者和订阅者,那么剩下的就比较简单了,就是要优雅关闭插件。在 v4 中并不支持这种操作。为了能实现动态热更新配置等场景,优雅关闭插件就很重要,因此设计的时候就考虑到了监听和退出监听的逻辑。因此在 sever 退出的时候,需要
退出所有发布者
退出所有订阅者
关闭所有插件的连接监听
关闭 server 级的 http 和 tcp 监听
所有这些对象都包含了可以用来退出的 context
通过传递一个 error 对象,可以用来标记退出的原因。
Server 热重启
本文所说的热重启并非极端意义的连接保持,那种极难实现
有了以上的铺垫,就可以用一个标记为重启的 error 对象来实现 server 的重启:
在重启时首先会优雅关闭 server,销毁所有资源,然后重新初始化 server 对象,读取配置,初始化插件对象,监听端口。就仿佛进程重启了一样。
实现热重启的好处
进程不再需要退出,对于错误处理更友好,对于 docker 容器来说,进程退出往往就会导致 docker 实例退出。此外重启速度更快,方便快速更新配置。另一个好处是结合多实例,对于单元测试和基准测试更方便,因为单元测试的时候不能退出进程,此时就可以启动多个 server 实例,进行测试,也可以关闭这些实例,测试其他内容。
版权声明: 本文为 InfoQ 作者【不卡科技】的原创文章。
原文链接:【http://xie.infoq.cn/article/8872a66cd734c17dccb75e1c4】。文章转载请联系作者。
评论