sidecar 注入失败导致 503,如何设计健康检查与自动重试
解读
在国内云原生落地场景中,Istio/Linkerd 等 Service Mesh 采用 Admission Webhook 在 Pod 创建阶段注入 sidecar。注入失败常因镜像拉取超时、Webhook 证书过期、集群网络策略阻断、资源配额不足或镜像仓库限流,导致 Pod 虽 Running 但缺少 sidecar,Envoy 未监听 15001/15090,此时业务容器一旦就绪即被 kubelet 加入 Endpoint,流量进入后无 sidecar 转发,直接返回 503 NC(No healthy upstream)。性能测试阶段若用默认 readinessProbe 仅检查业务端口,会把“缺 sidecar”的 Pod 误判为健康,压测流量瞬间打挂,SLA 直接击穿。因此需要把“sidecar 是否可用”纳入健康判断,并在失败链路里加入指数退避重试,既防止误判,又避免重试风暴。
知识点
- Kubernetes 探针机制:startupProbe、readinessProbe、livenessProbe 的执行顺序与生效条件。
- sidecar 生命周期:PostStart 钩子、iptables 初始化、Envoy 热重启、admin 接口 15000/15090 的可用性语义。
- 503 细分状态:UC(Upstream Connection)、NC(No healthy upstream)、NR(No route),对应不同根因。
- 指数退避与抖动:Full Jitter 算法防止 thundering herd,国内公有云 CLB 与 nginx-ingress 默认重试窗口 3 s 内。
- 性能测试视角:重试放大系数 = 并发数 × 重试次数,需用 TPS 预算反推最大重试次数,防止重试把后端打挂。
- 可观测性:istio_request_total{response_code="503", response_flags="NC"} 与 kube_pod_status_ready{condition="false"} 的关联规则。
答案
一、健康检查设计
-
双读探针
readinessProbe 同时检测业务端口与 sidecar admin 端口:- httpGet path=/healthz port=8080 (业务自身接口)
- httpGet path=/ready port=15090 (Envoy admin,返回 200 即 listener 已挂载)
使用 Pod 内共享网络命名空间,两个探针任一失败即置 Pod NotReady,kubelet 自动从 Endpoint 摘流,杜绝 503。
-
启动顺序兜底
在业务容器内增加 5 s 一次轮询,直到 curl -s 127.0.0.1:15000/clusters | grep inbound|grep healthy 返回 true 才继续启动 Tomcat/Netty,确保 sidecar 初始化完成后再监听业务端口,防止“先就绪后注入”的竞态。 -
集群级校验
在 CI 阶段用 istioctl verify-install 检查 MutatingWebhookConfiguration 的 failurePolicy 是否为 Fail、timeoutSeconds≤10 s,并保证 caBundle 未过期;同时用 kyverno 策略强制注入标签,防止“漏注”。
二、自动重试设计
-
客户端侧
在性能测试脚本(如 JMeter 或 Go 压测程序)里加入“503 NC”识别逻辑:当 response code=503 且 response body 包含 “no healthy upstream” 时触发重试,其余 503 直接报错。重试策略:- 退避:首次 200 ms,后续 ×2,上限 1.6 s,带 20% 随机抖动;
- 次数:单请求最多 3 次,总超时 2 s;
- 熔断:单 Pod 连续失败 5 次即标记为“坏点”,30 s 内不再向其发压测流量,防止重试放大。
-
网关侧
在 ingress-gateway 的 EnvoyFilter 中插入 retry_policy:
retry_on: “5xx,gateway-error,connect-failure,refused-stream”
num_retries: 2
per_try_timeout: 1.5s
retry_host_predicate: {name: envoy.retry_host_predicates.previous_hosts}
确保 503 NC 流量在网关层即被重试到其它可用 Pod,不会穿透到客户端。 -
性能预算验证
压测前先用 Little 定律估算:若目标 TPS=1000,重试次数期望值=0.1(注入失败率 1% × 2 次重试),则额外负载 ≤100 TPS,仍在后端 20% 安全余量内;若重试放大后 >10%,则优先修复注入链路而非继续调高重试。
三、灰度与回滚
在金丝雀阶段对注入失败 Pod 做 Chaos 注入(kubectl label ns default istio-injection=disabled 随机打标签),验证重试与健康检查是否能在 30 s 内自愈;若 P99 延迟上涨 >15% 或错误率 >0.3%,立即回滚 sidecar 版本并扩容副本,确保 SLA 不击穿。
拓展思考
- 多集群场景下,sidecar 镜像放在私有 Harbor 且跨 Region 同步延迟,注入失败率夜间陡增,如何设计镜像预热与就近缓存?
- 当应用使用 QUIC/HTTP3 直连,绕过 sidecar 的 iptables 拦截,健康检查如何感知“流量绕路”并触发告警?
- 在 Serverless 容器(如阿里云 ECI)中,Pod 冷启动 3 s 内 sidecar 尚未就绪,如何与弹性伸缩器联动,把“未注入”实例直接判为扩容失败,避免 503 被误统计为“业务错误”?