go语言优雅停机核心是用http.server.shutdown()配合信号监听与带超时的context:先捕获sigint/sigterm,再调shutdown拒绝新连接并等待活跃请求完成,超时后强制退出;同时需手动清理db、grpc等非http资源,并协同反向代理与k8s探针。

Go语言处理Web服务优雅停机,核心是让正在处理的请求完成、拒绝新请求、等待超时后强制退出。关键在于正确使用http.Server的Shutdown方法,并配合信号监听和上下文控制。
监听系统信号触发停机流程
服务需捕获SIGINT(Ctrl+C)和SIGTERM(如Kubernetes终止指令),避免直接退出。用signal.Notify监听,收到信号后启动停机逻辑:
- 关闭监听文件描述符(调用
srv.Close()或更推荐的srv.Shutdown()) - 停止接受新连接,但允许已建立连接继续处理请求
- 避免在信号处理中执行阻塞操作,应异步触发停机
调用Shutdown并设置合理的超时时间
srv.Shutdown(ctx)是优雅停机的主力方法,它会等待所有活跃连接完成。注意:
- 传入的
context.Context应带超时(如context.WithTimeout(context.Background(), 30*time.Second)),防止无限等待 - 若超时前仍有请求未结束,
Shutdown返回context.DeadlineExceeded,此时可记录日志,但进程仍需退出 - 不要在
Shutdown期间再起goroutine处理业务,它本身已协调连接关闭
提前通知反向代理或负载均衡器
生产环境中,优雅停机效果依赖上游组件配合:
- 在调用
Shutdown前,可通过健康检查接口返回失败(如/healthz返回503),让Nginx、ALB或K8s Endpoint Controller摘除该实例 - Kubernetes中建议配置
preStop钩子(如sleep 5),为应用留出缓冲时间,在发送SIGTERM前先从Endpoint移除 - 避免健康检查探针过于激进——比如设置2秒超时、1秒间隔,可能导致实例被过早剔除
清理非HTTP资源与等待自定义任务完成
除了HTTP服务器,服务常依赖数据库连接池、消息队列消费者、定时任务等。停机时需统一协调:
- 用同一
context传递给各组件(如db.Close()、redisPool.Close()),确保它们响应退出信号 - 对后台goroutine,用
sync.WaitGroup或errgroup.Group等待其自然退出;避免粗暴os.Exit() - 可在
Shutdown前调用自定义cleanup()函数,例如关闭gRPC服务、注销etcd租约等
不复杂但容易忽略:Shutdown不会自动关闭监听套接字,它只负责连接层面的 graceful 结束;而监听器关闭由ListenAndServe返回错误触发,因此务必确保主goroutine能捕获到该错误并进入停机流程。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











