← 中文资源

简体中文版本

不丢连接地优雅重载 nginx

用 nginx -s reload 配合正确的 worker 关闭参数,验证旧 worker 排空、配置变更期间零 502。

阅读英文原文

目标

nginx -s reload 会让新 worker 以新配置启动,并通知旧 worker 处理完手头请求后退出。做得对,进行中的请求毫发无伤,变更对客户端完全不可见。失败模式都很具体且可修:应用侧撕断 upstream 连接,或某个卡死的下载让古老 worker 永生。两者都只差一条指令。

步骤要点

  1. 记录 reload 前的 worker PID 列表作为基线。
  2. 让 hey 持续打流量,流量进行中执行 nginx -t && nginx -s reload,统计非 200 响应数。
  3. 五秒后再取 PID 列表,与基线求交集:交集为空说明旧 worker 已排空退出。
  4. 配置 worker_shutdown_timeout 10s 与 upstream keepalive,让慢客户端最多阻塞十秒、上游连接复用不误伤。
  5. 用 nginx -T 渲染最终配置核对变更确实生效,而不是 reload 成功但配置没变。

排错提示

reload 期间仍出 502 多是应用侧不优雅,要给 upstream 开 keepalive 并确认应用能排空连接;旧 worker 滞留几分钟是长请求挂住,务必设 worker_shutdown_timeout;reload 返回成功但行为没变,是配置校验失败而 nginx 保留了旧配置——前后都要跑 nginx -t 并读错误日志。

适用边界

reload 只换 worker,无法应用需要二进制升级的变更(如 nginx 大版本);WebSocket 等长连接可能被 shutdown_timeout 掐断,需与客户端重连逻辑协同。

代码示例

# The graceful handover
pgrep -f "nginx: worker" > /tmp/before
nginx -t && nginx -s reload
sleep 5
pgrep -f "nginx: worker" > /tmp/after
comm -12 /tmp/before /tmp/after | wc -l   # 0 = old workers drained