Linux 服务平滑下线的运维实现方案

1次阅读

服务下线需确保连接自然断开而非强制中断:通过监控ESTABLISHED连接下降、反向代理摘流、应用监听SIGTERM并优雅关闭、systemd配置TimeoutStopSec及健康检查、LB配合剔除流量,并验证端口释放、无活跃连接、注册状态清除。

Linux 服务平滑下线的运维实现方案

服务下线前如何确认连接已自然断开

直接 systemctl stop 或杀进程会导致活跃 TCP 连接被 RST 中断,客户端可能收到 “Connection reset by peer” 或超时失败。关键不是“停得快”,而是“等得清”。

  • ss -tuln state established | grep :netstat -tnp | grep : 观察当前 ESTABLISHED 连接数是否持续下降
  • http 服务,可临时在反向代理(如 nginx)中设置 proxy_next_upstream Error timeout http_502 并将该节点权重设为 0,让流量逐步摘除
  • 应用层需监听 SIGTERM,收到后关闭新连接入口(如 HTTP Server 的 srv.Close()),但保持旧连接直到自然结束或超时

如何用 systemd 实现可控的优雅终止窗口

默认 systemctl stop 只给 90 秒,且不等待应用真正释放端口和连接。必须显式配置超时与终止逻辑。

  • 在 service 文件中设置:
    TimeoutStopSec=300(延长终止等待时间)
    ExecStop=/bin/sh -c 'kill -TERM $MAINPID && sleep 2 && kill -CONT $MAINPID 2>/dev/NULL || true'(仅作示意,实际应由应用自身处理)
  • 更可靠的做法是:应用内实现 shutdown 流程,并在 ExecStop 中调用其健康检查接口(如 curl -f http://localhost:8080/healthz?ready=false)再等待连接归零
  • 避免使用 KillMode=none,它会让 systemd 放弃管理子进程,导致残留 worker 进程无法被回收

负载均衡器侧如何配合完成平滑摘流

服务端停了,但 LB 还在转发请求,就会产生 502/503。LB 不是旁观者,而是平滑下线的关键一环。

  • Nginx:先执行 upstream_haship_hash 配合 down 标记,再 reload;或用 max_fails=1 fail_timeout=10s 让健康检查快速剔除
  • consul:调用 PUT /v1/agent/service/deregister/,Consul 会先触发 TTL 失效、再通知所有 client 刷新本地缓存
  • kubernetes:修改 readiness probe 返回失败,再 kubectl scale deploy/ --replicas=0;确保 terminationGracePeriodSeconds ≥ 应用最大连接超时(如 300s)

验证下线是否真正完成的三个必查点

很多人以为 systemctl status 显示 inactive 就完事了,其实端口、连接、注册状态可能还挂着。

  • 查端口:lsof -i :ss -tlnp | grep : —— 必须无输出
  • 查连接:ss -tan state fin-wait-1,state fin-wait-2,state time-wait | grep : —— TIME-WAIT 是正常残留,但不应有 ESTABLISHED 或 CLOSE-WAIT
  • 查注册中心:curl http://consul:8500/v1/health/service/dig @.service.consul —— 确认服务条目已消失或状态为 critical

TIME-WAIT 状态本身不可怕,但若持续存在大量未回收连接,说明应用没正确调用 Close() 或设置了过短的 SO_LINGER,这会在高频下线场景中暴露资源泄漏问题。

text=ZqhQzanResources