滚动更新时反代实例请求丢失,本质是流量切换与容器生命周期未对齐;需协同就绪探针(真实业务就绪)、preStop钩子与terminationGracePeriodSeconds(保障优雅终止)、Service流量路由及滚动策略(maxUnavailable=0或maxSurge=1)三者逻辑。

滚动更新时反代实例请求丢失,本质是流量切换与容器生命周期没对齐。核心不在“能不能更新”,而在“新旧 Pod 何时可收、何时该停”。只要理清就绪探针、终止信号、Service 流量路由三者的协同逻辑,问题就能稳定收敛。
确保就绪探针(readinessProbe)真实反映服务可用性
很多反代(如 Nginx、Traefik)依赖 Kubernetes 的 Endpoints 或 EndpointSlices 投放流量。如果 Pod 启动后立即被标记为“就绪”,但实际 HTTP server 还没 bind 完、健康检查端口没响应、或连接池未初始化完成,请求就会 502/503。
- 就绪探针必须检查业务层真实就绪状态,例如:调用 /health/ready 接口并验证返回 200 + body 包含 "status": "UP"
- 避免用 exec 检查进程是否存在,或仅检查端口是否 open —— 这无法保证服务已加载配置、连上 DB 或 MQ
- 设置合理的 initialDelaySeconds(建议 10–30s)、periodSeconds(5–10s)和 failureThreshold(2–3),防止过早注入流量
强制优雅终止:preStop + terminationGracePeriodSeconds 配合使用
K8s 默认发送 SIGTERM 后等待 30 秒(terminationGracePeriodSeconds),但若容器内应用未监听或未处理该信号,会直接被 SIGKILL 强杀,正在处理的请求中断。
- 在容器中配置 preStop 生命周期钩子,例如执行 sleep 5 或调用 shutdown API,给应用留出缓冲时间
- 同步增大 terminationGracePeriodSeconds(如设为 60),确保它 ≥ 应用最长请求耗时 + preStop 执行时间
- 反代自身也需支持 graceful shutdown:Nginx 要用 nginx -s quit;Envoy 要配置 drain_timeout;Traefik 要启用 lifecycle.graceTimeOut
调整滚动更新策略,控制流量切换节奏
默认 maxUnavailable=25%、maxSurge=25% 可能导致瞬间多个旧 Pod 退出、新 Pod 尚未就绪,Service 后端列表短暂为空。
- 将 maxUnavailable 设为 0(即不允许任何 Pod 不可用),配合足够副本数(如 replicas≥3),确保旧 Pod 全部退出前,新 Pod 已全部 Ready 并接管流量
- 或者设 maxSurge=1 + maxUnavailable=0,先扩 1 个新 Pod,等它就绪后再缩 1 个旧 Pod,实现“先上后下”平滑过渡
- 避免在高并发时段触发更新;可结合 HPA 和自定义指标,在低峰期自动触发 rollout
反代与上游解耦:引入服务网格或带重试的客户端
即使 K8s 层面做到完美,网络抖动或瞬时 DNS 缓存也可能导致个别请求失败。增强容错需在更高层介入。
- 在反代侧配置 upstream retry(如 Nginx 的 proxy_next_upstream error timeout http_502;Envoy 的 retry_policy)
- 使用 Istio 等服务网格,开启 connection pool draining + outlier detection + automatic retries
- 客户端(如前端或网关)增加幂等重试逻辑(针对 GET/HEAD 安全重试;POST 建议带 idempotency-key)

















