Skip to content

第 4 章 · 健康检查

生活类比
被动检查 = 顾客走到柜台才发现收银员发烧了,只好换队——没人来排队时,生病的柜台可能一直「假开着」。
主动检查 = 经理每 5 分钟给每个员工测体温,37.5° 以上立刻安排休息,门口挂牌「暂停服务」——在顾客来之前就知道谁不能上班


4.1 为什么需要健康检查?

负载均衡器维护一个「后端池」。如果池里有一台 已经宕机但还被分配流量 的机器:

10 个请求 → LB 轮询 → 其中 3~4 个打到死机 → 用户看到 502/超时

健康检查(Health Check) 的作用:持续判断后端是否 真的能干活,把不健康的节点 临时摘除,恢复后再 加回


4.2 两种检查方式

被动健康检查(Passive)

在真实业务流量中 观察失败,失败次数够了就标记不可用。

Nginx 开源版典型配置:

nginx
upstream backend {
    server 10.0.0.1 max_fails=3 fail_timeout=30s;
    server 10.0.0.2 max_fails=3 fail_timeout=30s;
}
参数含义
max_fails=3fail_timeout 窗口内失败 3 次 → 标记 down
fail_timeout=30s标记 down 持续 30 秒,之后再放行试探

优点:零额外探针流量,配置简单
缺点

  • 没流量时不会发现 后端已挂(僵尸节点)
  • 要靠 真实用户请求失败 才能感知——等于拿用户当探针
  • 刚启动的后端可能还没就绪就被打入流量

主动健康检查(Active)

LB 定期主动 发探测请求,不依赖业务流量。

nginx
# Nginx Plus / Tengine / OpenResty 等扩展支持
upstream backend {
    server 10.0.0.1;
    health_check uri=/healthz interval=5s fails=3 pass=2;
}

应用需提供轻量探针接口:

go
// GET /healthz → 200 表示进程活着且依赖 OK
func healthz(w http.ResponseWriter, r *http.Request) {
    if db.Ping() != nil {
        w.WriteHeader(503)
        return
    }
    w.WriteHeader(200)
    w.Write([]byte("ok"))
}

优点:提前发现故障、支持预热、可检查依赖(DB、Redis)
缺点:额外探针 QPS、要规范探针接口

对比表

被动主动
发现速度慢(等有流量失败)快(定时探)
无流量时发现不了能发现
实现Nginx 开源自带常需 Plus/Tengine/云 LB
生活类比病人来了才量体温上班前统一体检

4.3 探针类型

类型检查什么典型命令/配置
TCP 探针端口能否建立连接nc -zv 10.0.0.1 8080
HTTP 探针返回码是否 2xxGET /healthz 期望 200
HTTPS 探针TLS + HTTP云 LB 控制台配置
gRPC 健康检查grpc.health.v1K8s gRPC probe
自定义脚本任意逻辑检查磁盘、队列深度

TCP vs HTTP 探针怎么选?

进程活着但死锁 → TCP 探针仍通过 ✗
进程活着且能正确响应 /healthz → HTTP 探针 ✓

生产建议:HTTP 探针 + 检查关键依赖,而不是只探端口。


4.4 健康检查参数(通用概念)

参数含义设太小设太大
interval探测间隔探针风暴发现慢
timeout单次超时误杀僵死检测慢
healthy_threshold连续成功几次算健康频繁上下线恢复慢
unhealthy_threshold连续失败几次算不健康误杀(网络抖动)死节点流量多

生活例子

员工体温测量:

  • 5 分钟 测一次(interval)
  • 一次测量等 10 秒 出结果(timeout)
  • 连续 2 次 正常才返岗(healthy_threshold)
  • 连续 3 次 超标才休息(unhealthy_threshold)

4.5 优雅下线(Graceful Shutdown)

健康检查不只「发现挂了」,还要支持 主动维护

1. 运维对节点 A 执行「下线」
2. LB 立刻把 A 标为 draining(不再分配新请求)
3. 等 A 上已有请求处理完(等待 N 秒)
4. A 进程退出
5. 用户全程无感知

K8s 中的体现:

yaml
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 15"]  # 给 LB 时间摘流量

生活例子:收银员下班前,门口牌写「本窗口停止接待新客户」,但 把手上的客户办完 再关窗。


4.6 备用节点(Backup)

nginx
upstream backend {
    server 10.0.0.1;
    server 10.0.0.2;
    server 10.0.0.99 backup;   # 仅当 1、2 都不可用时启用
}

适合 冷备机、灾备机房,平时不浪费流量。


4.7 常见故障场景

场景 1:假死(进程在但不响应)

  • 症状:TCP 能连,HTTP 超时
  • 对策:HTTP 探针 + 合理 timeout;应用 /healthz 要真检查业务

场景 2:启动未就绪就被打入流量

  • 症状:发布瞬间大量 502
  • 对策:readiness probe(K8s)/ 启动预热期 / weight 从 0 渐增

场景 3:网络抖动导致误杀

  • 症状:节点一会儿 up 一会儿 down(flapping)
  • 对策:增大 unhealthy_threshold、用多 AZ 探针

场景 4:探针路径被鉴权拦住

  • 症状:业务正常但探针 401,节点被误摘
  • 对策:/healthz 放行白名单,不走登录校验

4.8 与熔断、降级的关系

健康检查:这台机器还能不能接客?     → 摘除单个节点
熔断:     调用方发现错误率太高       → 暂时不调整个服务
降级:     能力不够时返回兜底数据     → 保证核心可用

生活类比

  • 健康检查:某个收银台关了
  • 熔断:整条零食货架暂时不补货,避免拖累整个店
  • 降级:生鲜没了,先卖常温食品

4.9 实战 Checklist

  • [ ] 有独立 /healthz,检查 DB/缓存等关键依赖
  • [ ] 探针路径不走重逻辑(别查全表)
  • [ ] 主动健康检查(云 LB 或 Tengine/APISIX)
  • [ ] 发布时优雅下线 + readiness
  • [ ] 监控「后端池健康节点数」告警

4.10 一句话总结

被动检查靠用户踩雷,主动检查靠经理巡检——生产环境请选主动;探针要真探业务,别只探端口。

下一章 → 05 · 会话与粘性