endless是如何实现graceful restart

什么是graceful restart

能够优雅的重启,可以处理未处理完的request, 保证服务不中断

graceful restart需要做的事

  • 重启服务期间可以确保待处理的request能够得到处理(完成或超时)
  • 不关闭已经打开的socket连接(重用socket)

endless的实现思路

image

  • 通过endlessListener重载http.Server.Accept(), 每接收一下request, sync.WaitGroup.Add(1)
  • 通过endlessConn重载http.conn.Close(), 当一个request被处理, sync.WaitGroup.Done()
  • endlessServer.Serve() 通过sync.WaitGroup.Wait()等待所有已接收的request处理完毕
  • 当接收到SINGHUP信号时,fork一个子进程,将当前运行的程序重新执行,并通过环境变量ENDLESS_CONTINUE=1来告知这是子进程。当检测到是子进程时,通过syscall.Kill(syscall.Getppid(), syscall.SIGTERM)来关闭父进程
  • 协程handleSignals通过for循环监听到SIGINTSIGTERM信号,shutdown endlessServer, close endLessListener, 此时退出http.Server.Serve()for循环,执行srv.wg.Wait()
  • 等待父进程处理完所有request,或者通过endlessServer.hammerTime(), sleep指定时间后,for循环调用WaitGroup.Done(),强制结束

测试

fvbock/endless提供了example, 按照文档所说去一步步执行,可以观察到预料的实验现象。 注意kill -1 $pid 是指发送HUP信号到$pid进程。

kill时的数字对应信号信息如下:
image

所以很容易理解kill -9 $pid强制杀死$pid进程其实就是发送KILL信号给$pid进程。