背景
裸重启进程很简单,但线上会带来短暂不可用。优雅重启的目标是:
- 停止接收新连接
- 等待在途请求处理完
- 平滑切换到新进程
Go 侧的退出处理
srv := &http.Server{Addr: ":8080", Handler: mux}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
_ = srv.Shutdown(ctx)
Shutdown 会先关闭监听,再等待连接收尾。
systemd 关键配置
[Service]
ExecStart=/opt/app/server
Restart=always
RestartSec=2
TimeoutStopSec=20
KillSignal=SIGTERM
KillSignal=SIGTERM给应用机会走优雅退出逻辑TimeoutStopSec要大于应用Shutdown超时
发布建议
- 先在网关层摘流量
- 再重启实例
- 观察错误率与连接数回落
小结
优雅重启不是一个函数调用,而是应用与进程管理器协同设计。把退出路径做好,发布风险会明显下降。