GKE环境Node.js应用readinessProbe失败排查与零停机配置方案
问题根因
探测频率不符合配置预期的原因
你观测到的每秒3次探测请求,并非全部来自kubelet的readinessProbe,实际是三类健康检查流量叠加的结果:
- kubelet本身的探针重试机制:探针请求失败后不会等待下一个
periodSeconds周期,会立刻发起重试,直到达到failureThreshold阈值才会更新就绪状态 - GKE Service层自带的健康检查:kube-proxy会对每个后端Pod端口做周期性连通性校验
- GKE Ingress控制器独立的健康检查:默认以1秒/次的频率探测后端Pod,和kubelet探针完全独立,不会使用你在Pod配置里定义的探测参数
三类流量叠加后,实际到达Pod的探测请求频率远高于配置的3秒1次。
偶发连接拒绝、流量被阻断的原因
故障本质不是应用层限流导致,是多层问题叠加触发的误摘除:
- Node.js单线程事件循环在运行过程中会出现偶发的短暂阻塞:比如老生代GC停顿、大响应体序列化、节点CPU被同节点其他负载抢占、瞬时IO打满,阻塞时长一旦超过探针配置的3秒超时时间,内核层面的TCP连接队列就会被堆积的探测请求打满,新到的探针请求会被内核直接返回
connection refused,根本到不了Express应用层,所以你排除Express限流规则后故障依然会复现。 - 原配置中readinessProbe的
failureThreshold使用默认值3,超时时间仅3秒,只要连续3次探测(算上重试实际仅需数秒)失败,kubelet就会把Pod从Service Endpoints列表中摘除,Ingress也会同步停止转发流量,导致业务完全中断。 - 最初观测到的429报错,是阻塞时间较短时请求能到达Express层、触发限流规则的表现,和后续的连接拒绝是同一个根因的不同阶段表现。
零停机部署最佳配置方案
代码层调整
- 拆分健康检查端口:在业务端口(3003)之外,单独启动一个极简HTTP服务监听独立端口(比如3004),不接入任何Express业务中间件,所有请求直接返回200状态码,完全不受业务逻辑阻塞影响,专门用于kubelet和Ingress的运行时健康检查。
- 启动检查逻辑保留在业务端口:
/health/startup路径仅在服务启动阶段校验DB、缓存等强依赖连接状态,服务启动完成后不再执行重依赖校验,避免运行时DB抖动导致Pod被误摘。 - 启动HTTP服务时调整TCP backlog参数,将默认的128调整为511,避免突发探测请求打满内核连接队列,示例:
// 业务服务 app.listen(3003, '0.0.0.0', 511, () => { console.log('Business server running on 3003') }) // 独立健康检查服务 const healthServer = require('http').createServer((req, res) => res.end('ok')) healthServer.listen(3004, '0.0.0.0', 511)
K8s资源配置调整
- 探针配置参考如下,兼顾启动灵活性和运行时稳定性:
startupProbe: httpGet: path: /health/startup port: 3003 initialDelaySeconds: 0 periodSeconds: 2 timeoutSeconds: 2 failureThreshold: 30 # 最长容忍60秒启动时间,适配冷启动、慢DB连接场景 successThreshold: 1 readinessProbe: httpGet: path: / port: 3004 initialDelaySeconds: 0 periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 5 # 连续10秒探测失败才摘除流量,过滤偶发卡顿 successThreshold: 1 livenessProbe: httpGet: path: / port: 3004 initialDelaySeconds: 10 # startupProbe成功后再启动存活检查 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 6 # 连续1分钟无响应才重启进程,避免误重启 successThreshold: 1 lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 3; kill -TERM 1"] # 等待3秒让流量规则同步完成再终止进程
- 为Pod配置匹配实际负载的CPU、内存requests值,避免节点资源超卖时业务进程被抢占CPU导致事件循环阻塞。
- 若使用GCE原生Ingress,手动将Ingress后端健康检查的探测间隔调整为5秒、超时2秒、不健康阈值5次,探测路径指向3004健康检查端口,和Pod侧探针规则对齐,避免Ingress侧提前摘除流量。
内容的提问来源于stack exchange,提问作者Raz Buchnik
相关产品推荐
相关产品推荐

