服务优雅下线为什么重要?
简化版
优雅下线先停止接收新流量,再等待在途请求、消息和事务完成,最后释放资源并退出,从而避免发布或缩容制造大量 5xx、重复消费和半完成操作。 正确顺序是“标记不就绪/摘流—传播等待—停止接新任务—排空—超时取消—释放”,且必须有总时限和幂等恢复。
详细版
收到 SIGTERM 后,实例先让 readiness 失败并从注册中心摘除,但负载均衡、客户端缓存和长连接不会瞬间收敛,因此要留传播窗口。随后关闭监听或拒绝新业务,请求计数归零、消息 consumer 停止拉取并提交已完成位点,数据库事务结束后再关连接池。
若平台给 30 秒终止期,可预留 5 秒摘流传播、20 秒排空、5 秒强制取消和清理。超过 deadline 的工作不能无限拖住发布;有副作用任务应保存状态或回队,并依靠幂等键防重复。监控 active requests、排空耗时、强杀数和退出期间错误率。
完整版教学
一、直接杀进程会发生什么
负载均衡器仍可能向已退出实例发请求,进行中的 HTTP/RPC 被断开,消息处理完但位点未提交会再次消费,事务可能回滚而上游结果未知。滚动发布若每批都制造这些错误,会把正常变更变成小型事故。
记忆钩子:摘流解决“别再来”,排空解决“手里的做完”,幂等解决“没做完又来一次”。
二、正确的退出状态机
RUNNING -> DRAINING -> QUIESCED -> CLEANING -> EXITED
| 超过总期限
+---------------> FORCE_CANCEL -> EXITED
状态切换只允许单向,重复 SIGTERM 不应重复关闭资源。健康检查要区分 liveness 与 readiness:下线时 readiness 失败用于摘流,liveness 仍成功,避免平台误判并立即强杀。
三、为什么摘流后仍要等待
注册中心推送、DNS、sidecar 和客户端连接池都有传播延迟。假设客户端每 10 秒刷新一次实例列表,摘流后至少等待一个刷新周期再关闭监听,才能减少新请求命中。HTTP/2、WebSocket 等长连接还需 GOAWAY/关闭通知,让客户端迁移连接。
| 协议/任务 | 停止新工作方式 | 排空判断 |
|---|---|---|
| HTTP/1.1 | 停监听/Connection close | active=0 |
| HTTP/2 | GOAWAY | stream=0 |
| MQ Consumer | pause 拉取 | handler=0且位点提交 |
| 定时任务 | 撤销调度租约 | 当前执行结束/转移 |
四、消息和事务的特殊边界
Consumer 应先停止 poll,再处理已拉取消息,业务提交成功后提交 offset。若同一分区内并行处理,提交的必须是“连续完成位置”,不能因为后面的消息先完成就越过尚未完成的消息。若先提交 offset 再完成业务,强杀会丢消息;若业务完成后未提交 offset,重启会重复,因此消费者必须幂等。长事务要受 shutdown deadline 限制,并记录未知状态供恢复任务查询。
pause -> drain handlers -> commit completed offsets -> close consumer
五、终止时间怎样分配
Kubernetes terminationGracePeriodSeconds=30 时,可将 5 秒用于摘流传播、20 秒用于在途请求、5 秒用于取消与资源关闭。接口自身 timeout 若为 60 秒,就与平台终止期冲突,应缩短请求 deadline 或扩大终止期。
排空不是无限等待。到期任务应取消、重新入队或保存恢复点;不能为追求“优雅”阻塞整个发布。强杀率持续大于 0 说明预算或代码有问题。
六、滚动发布和容量
发布时下线实例会减少容量。10 个实例每个 200 QPS,当前流量 1600 QPS;一次下线 3 个只剩 1400 QPS 容量,会在排空前就过载。maxUnavailable、预热和摘流批次必须与冗余容量一致。
监控包括终止信号到摘流时间、新请求命中 draining 实例数、active、排空 P95、强杀数、重复消费和发布错误率。演练同时覆盖正常发布、节点突然断电和控制面失联,因为优雅流程不能替代异常恢复。
七、常见误区与追问
- 误区:从注册中心删除后立即没有流量。 客户端缓存和长连接仍可能继续发送。
- 误区:readiness 失败后 liveness 也应失败。 后者可能触发强杀,破坏排空。
- 误区:一直等待就是最优雅。 发布有总 deadline,超时任务需要可恢复地终止。
- 误区:消息处理排空后一定不会重复。 业务完成与 offset 提交之间仍可能崩溃,必须幂等。
- 追问:长连接怎样下线? 发送 GOAWAY/服务关闭通知,停止新 stream,并给客户端重连时间。
- 追问:新流量仍到旧实例怎么办? 保持短期服务或返回可重试错误,同时排查传播层,而不是直接退出。
- 追问:进程被 SIGKILL 怎么办? 依靠事务、租约、幂等和消息重投恢复,优雅下线无法覆盖硬故障。
八、加强记忆
优雅下线按“先摘流、等传播、停新活、排旧活、到期可恢复、最后关资源”执行。readiness 与 liveness 分工,HTTP、长连接、MQ 和定时任务分别排空,再用发布容量和强杀指标验证。它降低计划变更错误,但硬故障仍需幂等和恢复机制兜底。