- 背景
- golang 程序平滑重启框架
- supervisor 出现 defunct 原因
- 使用 master/worker 模式
背景
在业务快速增长中,前期只是验证模式是否可行,初期忽略程序发布重启带来的暂短停机影响。当模式实验成熟之后会逐渐放量,此时我们的发布停机带来的影响就会大很多。我们整个服务都是基于云,请求流量从 四层->七层->机器。
要想实现平滑重启大致有三种方案,一种是在流量调度的入口处理,一般的做法是 ApiGateway + CD ,发布的时候自动摘除机器,等待程序处理完现有请求再做发布处理,这样的好处就是程序不需要关心如何做平滑重启。
第二种就是程序自己完成平滑重启,保证在重启的时候 listen socket FD(文件描述符) 依然可以接受请求进来,只不过切换新老进程,但是这个方案需要程序自己去完成,有些技术栈可能实现起来不是很简单,有些语言无法控制到操作系统级别,实现起来会很麻烦。
第三种方案就是完全 docker,所有的东西交给 k8s 统一管理,我们正在小规模接入中。
golang 程序平滑重启框架
与 java、net 等基于虚拟机的语言不同,golang 天然支持系统级别的调用,平滑重启处理起来很容易。从原理上讲,基于 linux fork 子进程的方式,启动新的代码,再切换 listen socket FD,原理固然不难,但是完全自己实现还是会有很多细节问题的。好在有比较成熟的开源库帮我们实现了。graceful https://github.com/tylerb/graceful
endless https://github.com/fvbock/endless
上面两个是 github 排名靠前的 web host 框架,都是支持平滑重启的,只不过接受的进程信号有点区别 endless 接受 signal HUP,graceful 接受 signal USR2 。graceful 比较纯粹的 web host,endless 支持一些 routing 的能力。
我们看下 endless 处理信号。(如果对 srv.fork() 内部感兴趣可以品读品读。)