滚动更新时nginx长连接未断导致502/超时,根源是k8s与nginx协同失效;需pod优雅终止(prestop+graceful shutdown)、nginx配置proxy_next_upstream与keepalive超时、改用ingress controller或动态同步endpoints。

滚动更新时 Nginx 反向代理的长连接无法自动断开,本质是后端 Pod 被终止但前端 Nginx 仍维持 TCP 连接,导致新请求被转发到已停止处理的旧实例,出现超时或 502 错误。这不是 Nginx 配置遗漏,而是 Kubernetes 与 Nginx 协同机制未对齐所致。
确保后端 Pod 优雅终止并等待连接清理
Pod 收到 SIGTERM 后必须主动拒绝新建连接、并持续处理已有长连接直至完成。Nginx 作为客户端时,依赖后端服务的关闭行为;若后端(如 Java/Node.js 服务)直接退出而未 drain 连接,Nginx 就会继续往“空壳”发包。
- 在容器中配置 preStop hook,例如执行
sleep 15或调用业务 shutdown 接口,为长连接留出处理时间 - 设置 terminationGracePeriodSeconds ≥ preStop 执行时长 + 最大连接处理耗时(建议至少 30 秒)
- 应用层需实现 graceful shutdown:监听 SIGTERM、停止接受新请求、等待活跃连接自然结束或强制超时关闭(如 Netty 的
shutdownGracefully())
调整 Nginx 主动探活与连接复用策略
Nginx 默认复用后端连接(keepalive),若不干预,可能把请求发给已终止但连接尚未断开的旧 Pod。需让 Nginx 更快感知后端失效。
- 启用 keepalive_timeout 和 proxy_next_upstream,例如:
proxy_next_upstream error timeout http_502;
proxy_next_upstream_tries 3;
keepalive_timeout 60s; - 对 upstream 配置 max_fails=1 fail_timeout=10s,加速剔除异常节点
- 避免全局开启
proxy_http_version 1.1+proxy_set_header Connection ''后未配 keepalive,否则可能造成连接池僵死
利用 Service 层信号同步切断连接路径
Kubernetes 的 Endpoint 变更存在延迟,Nginx 若直连 ClusterIP Service,可能因缓存或异步同步错过 Pod 下线事件。应让 Nginx 感知真实后端状态。
- 推荐改用 Ingress Controller(如 nginx-ingress):它 watch Endpoints 变化,秒级重载 upstream,天然支持优雅摘流
- 若自建 Nginx,可配合 Endpoint 监控 + 动态配置生成工具(如 consul-template、envoy xDS),而非静态写死 endpoints
- 禁用
proxy_buffering off时尤其注意,未缓冲响应体易加剧长连接残留问题
验证连接生命周期是否对齐
滚动更新过程中,可通过日志和连接跟踪确认关键环节是否按时序生效:
- 检查旧 Pod 的 preStop 是否执行、SIGTERM 是否收到、容器是否在 terminationGracePeriodSeconds 结束后才被 kill
- 在 Nginx 容器内执行
ss -tnp | grep :80,观察 ESTABLISHED 连接是否随旧 Pod 终止而逐步减少 - 开启 Nginx
error_log debug,搜索upstream timed out或no live upstreams,定位失败转发点











