Open wangming1993 opened 7 years ago
https://grisha.org/blog/2014/06/03/graceful-restart-in-golang/ https://github.com/fvbock/endless https://github.com/fvbock/endless/tree/master/examples
能够优雅的重启,可以处理未处理完的request, 保证服务不中断
endlessListener
http.Server.Accept()
sync.WaitGroup.Add(1)
endlessConn
http.conn.Close()
sync.WaitGroup.Done()
endlessServer.Serve()
sync.WaitGroup.Wait()
SINGHUP
fork
ENDLESS_CONTINUE=1
syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
handleSignals
for
SIGINT
SIGTERM
http.Server.Serve()
srv.wg.Wait()
endlessServer.hammerTime()
WaitGroup.Done()
fvbock/endless提供了example, 按照文档所说去一步步执行,可以观察到预料的实验现象。 注意kill -1 $pid 是指发送HUP信号到$pid进程。
kill -1 $pid
HUP
$pid
kill时的数字对应信号信息如下:
所以很容易理解kill -9 $pid强制杀死$pid进程其实就是发送KILL信号给$pid进程。
kill -9 $pid
KILL
什么是graceful restart
能够优雅的重启,可以处理未处理完的request, 保证服务不中断
graceful restart需要做的事
endless的实现思路
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
循环监听到SIGINT
或SIGTERM
信号,shutdown endlessServer, close endLessListener, 此时退出http.Server.Serve()
的for
循环,执行srv.wg.Wait()
endlessServer.hammerTime()
, sleep指定时间后,for
循环调用WaitGroup.Done()
,强制结束测试
fvbock/endless提供了example, 按照文档所说去一步步执行,可以观察到预料的实验现象。 注意
kill -1 $pid
是指发送HUP
信号到$pid
进程。kill时的数字对应信号信息如下:
所以很容易理解
kill -9 $pid
强制杀死$pid
进程其实就是发送KILL
信号给$pid
进程。