Golang HTTP服务在上线时,需要重新编译可执行文件,关闭正在运行的进程,然后再启动新的运行进程。对于访问频率比较高的面向终端用户的产品,关闭、重启的过程中会出现无法访问(nginx表现为502)的情况,影响终端用户的使用体验。

实现的一般思路

一般情况下,要实现平滑重启或升级,需要执行以下几个步骤:

  1. 发布新的bin文件覆盖老的bin文件

  2. 发送一个信号量(USR2),告诉正在运行的进程,进行重启

  3. 正在运行的进程接受到信号后,以子进程的方式启动新的bin文件

  4. 新进程接收并处理新的请求

  5. 老进程不再接收新请求,等待所有正在处理的请求处理完成后自动退出

  6. 新进程在老进程退出后,继续提供服务

选型与实践

重复造平滑重启及升级的轮子比较简单,但测试覆盖无法控制,比较耗时耗力。所以秉着不重复造轮子的思路,使用github中的三方库进行选择:

  • facebookgo/grace

  • fvbock/endless

  • jpillora/overseer

facebookgo/grace
func (h *Server) ListenAndServe(listenAddress string) error {
    
// ....
return gracehttp.Serve(&http.Server{
Addr: listenAddress,
Handler: h.httpServerMux,
})
}
abapi-publish
ab -c 10 -n 2000 http://127.0.0.1:38272/api/list
USR2kill -USR2 api-server-pi