什么是“优雅关闭”(Graceful Shutdown)

1. 什么是“优雅关闭”(Graceful Shutdown)

优雅关闭指的是:在系统或服务停止时,不立刻粗暴地中断进程,而是有秩序地完成“善后工作”,再安全退出
它的核心目标只有一个:不丢数据、不伤用户、不留烂摊子

可以把它想成餐厅打烊:不再接新客 → 让已入座的客人吃完 → 结账 → 关灯锁门,而不是直接拉闸断电。


1.1 优雅关闭解决的本质问题

  • 正在处理的请求怎么办
  • 正在写的数据是否会损坏
  • 上游/下游是否感知到服务已下线
  • 集群整体是否还能保持稳定

2. 没有优雅关闭会发生什么

2.1 对业务的影响

  • HTTP 请求直接被中断,用户看到 502 / 504
  • 事务未提交,产生脏数据或数据不一致
  • 消息消费一半,导致重复消费或消息丢失

2.2 对系统的影响

  • 连接未释放(TCP、DB 连接池)
  • 文件句柄、锁未释放
  • 集群误判为异常宕机,引发级联故障

一句话总结:暴力退出是技术债,优雅关闭是工程素养


3. 优雅关闭的标准流程

3.1 阶段一:停止接收新请求

  • 负载均衡 / Service Mesh / Ingress 摘除流量
  • 应用层返回“即将下线”信号

3.2 阶段二:处理完已存在的工作

  • 等待正在执行的 HTTP 请求完成
  • 等待 Goroutine / Thread / Worker 收尾
  • 消费完已拉取的消息

3.3 阶段三:资源释放与状态持久化

  • Flush 缓存 / 日志
  • 提交或回滚事务
  • 关闭 DB、MQ、Redis 连接

3.4 阶段四:进程退出

  • 返回 0,告诉系统:我不是“死的”,我是“退役的”

4. 在 Linux / 容器世界里的体现

4.1 信号语义

  • SIGTERM:请你体面地退出(优雅关闭的起点)
  • SIGKILL:我没耐心了,直接掐死(没有任何清理机会)

4.2 Docker / Kubernetes 的行为

  • docker stop → 先发 SIGTERM,再等 timeout

  • K8s Pod 删除流程:

    • Endpoint 下线
    • 发送 SIGTERM
    • terminationGracePeriodSeconds
    • 超时才 SIGKILL

5. 典型的优雅关闭架构

sequenceDiagram
    participant User
    participant LB as LoadBalancer
    participant Pod
    participant App

    User->>LB: 请求
    LB->>Pod: 转发请求
    Pod->>App: 处理

    Note over Pod,App: Pod 被删除
    LB-->>Pod: 停止转发新流量
    Pod->>App: SIGTERM
    App->>App: 等待正在处理的请求
    App->>App: 释放资源/Flush
    App-->>Pod: 正常退出

6. 不同系统中的“优雅关闭”侧重点

6.1 Web 服务

  • 请求不被中断
  • KeepAlive 连接平滑关闭

6.2 消息系统(Kafka / RabbitMQ)

  • 不再拉新消息
  • 已消费消息确认(ACK)

6.3 数据库 / 存储

  • Flush WAL / Buffer
  • 保证一致性点

7. 一个工程师视角的判断标准

如果一个服务具备以下能力,基本算“合格”:

  • 能正确处理 SIGTERM
  • 能配置最大优雅关闭时间
  • 在关闭期间对用户无明显感知
  • 日志中能清晰看到 shutdown 过程