背景

裸重启进程很简单,但线上会带来短暂不可用。优雅重启的目标是:

  • 停止接收新连接
  • 等待在途请求处理完
  • 平滑切换到新进程

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 超时

发布建议

  1. 先在网关层摘流量
  2. 再重启实例
  3. 观察错误率与连接数回落

小结

优雅重启不是一个函数调用,而是应用与进程管理器协同设计。把退出路径做好,发布风险会明显下降。