3. 健康检查入门:健康检查的目的、被动健康检查与主动健康检查的区别
你想想看,负载均衡器把流量分发到多台后端服务器,听起来很美好。但万一其中一台服务器已经挂了,或者正在半死不活地响应超时呢?
负载均衡器如果还傻乎乎地继续往那台机器发请求,那用户的体验就是——页面转圈、报错、甚至连接被重置。
嗯,这就是健康检查要解决的问题。
3.1 健康检查的底层逻辑
说白了,健康检查就是负载均衡器用来判断后端节点“是死是活”的一套探测机制。它不是锦上添花,而是系统的底线。
我个人习惯把健康检查的目的归纳为三点:
- 踢掉坏节点——当后端服务异常时,立即将其移出转发池
- 恢复后自动接入——节点恢复正常后,重新加入服务
- 保证新节点可用——新加入的机器先检查再上线,不直接接流量
我在项目中遇到过好几次极端情况——比如某次线上压测,一台机器的CPU飙到95%,但TCP端口还活着。如果用简单的端口检查,这台机器仍然是“健康的”。但实际呢?请求进去全卡住。这就是为什么健康检查不能只看表面。
3.2 被动健康检查
被动健康检查,也叫“懒汉检查”。它不主动去探测后端,而是通过监控真实流量的表现来做判断。
举个例子——负载均衡器把请求发给后端A,结果返回了5xx状态码。被动检查就会记录这次失败。当失败次数达到一个阈值时,就把A标记为不健康,暂时踢出转发池。
它的核心机制就几个点:
- 观测指标:响应状态码(4xx/5xx)、超时、连接失败、TLS握手失败
- 统计窗口:比如最近30秒内的失败率
- 淘汰阈值:连续N次失败,或失败率超过X%
- 恢复策略:经过一段冷却时间后,重新尝试转发少量请求做“试探”
为什么叫“被动”?因为它不产生额外的探测流量。所有判断都基于用户请求的结果。这样做的好处很直观——不浪费带宽,不增加系统开销,尤其在加密服务场景下,主动探测也要走TLS握手,成本不低。所以很多团队在低配环境下优先选择被动检查。
但被动检查有个明显的短板:判断滞后。
假设后端在两次请求之间挂掉了。下一次用户请求正好打到这台机器上,才会触发探测失败。也就是说,那第一个用户就倒霉了。在高可用场景下,这通常是不可接受的。
3.3 主动健康检查
主动健康检查,是更“积极”的方式。负载均衡器会定时向后端服务器发送专门的探测请求,不管有没有用户流量,都一直测。
这种探测可以是:
- ICMP Ping(网络层)
- TCP连接测试(传输层)
- TLS握手测试(针对加密服务)
- HTTP/HTTPS请求应用层接口(例如
GET /health) - 自定义脚本或gRPC健康检查
主动检查的好处很明显——能在流量到达之前发现问题。后端刚启动好,还在预热?主动检查就知道它还没就绪,不会把流量分过去。后端突然挂了?下一轮探测(一般是1-5秒间隔)就能检测到,立刻踢掉。
在加密服务里,主动检查有个特殊场景。我建议每个HTTPS后端都暴露一个/health接口,并且这个接口的证书验证和业务完全一致。这样探测结果才能真正反映客户端眼看的世界。
# NGINX配置示例 —— 主动健康检查
upstream backend {
zone backend 64k;
server backend1.example.com:443;
server backend2.example.com:443;
# 主动健康检查
health_check interval=5s fails=3 passes=2;
# 指定检查路径与Host
health_check uri=/health;
health_check mandatory;
}
# 对应的后端health接口可以返回200和简单JSON
location /health {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
但主动检查不是免费的。每一次探测都消耗连接、可能还要做TLS握手,频繁了会加重后端负担。检查间隔太长,又失去了“提前发现”的意义。所以要在检测灵敏度和系统开销之间做取舍。
3.4 对比:被动 vs. 主动
这两种方式不是二选一。我参与过的生产项目中,绝大多数成熟方案都是两者并用的。它们互相弥补短板。
| 维度 | 被动健康检查 | 主动健康检查 |
|---|---|---|
| 探测方式 | 基于真实用户请求的响应 | 定时发送独立探测请求 |
| 额外开销 | 几乎为零 | 产生探测流量,TLS握手成本 |
| 发现故障速度 | 慢,取决于用户请求到达 | 快,可配置短间隔 |
| 适用场景 | 流量已满的集群、成本敏感环境 | 高可用要求、新节点上线、冷启动 |
| 检测深度 | 仅限请求层面(状态码、超时) | 可到应用层(接口返回值验证) |
| 漏检风险 | 如果节点无用户流量,故障不会被发现 | 探测请求与实际用户请求路径可能不一致 |
看到了吗?两个都有盲区。主动检查可能测到health接口正常,但实际业务接口已经坏了——比如数据库挂了,只有health接口没连数据库。被动检查能真实反映业务请求到底好不好用,但第一波用户已经受伤了。
3.5 组合策略才是王道
我个人习惯用主动检查做快速发现,用被动检查做有效性验证。
具体流程是这样的:
- 主动检查每3秒探测一次所有后端,一旦连续失败,立即标记为“不健康”并踢出
- 被踢出的后端仍然接受低频率的主动探测(比如每10秒一次)
- 恢复后后端重新加入转发池,但会先接收少量流量
- 被动检查持续监控真实请求的表现,如果发现刚恢复的节点再次大量5xx,会再次踢出
你看,主动检查负责“快”,被动检查负责“准”。
在HAProxy里,这种组合有直接的关键字支持:
# HAProxy配置 —— 主动+被动组合
backend servers
balance roundrobin
# 主动检查(每2秒一次,连续3次失败标记down)
option httpchk GET /health HTTP/1.1\r\nHost:\ example.com
default-server inter 2s fall 3 rise 2
server srv1 10.0.0.1:443 check inter 2s fall 3 rise 2 weight 100
server srv2 10.0.0.2:443 check inter 2s fall 3 rise 2 weight 100
# 被动检查(连续10次5xx则剔除此后端1分钟)
option redispatch
retries 3
timeout connect 5s
为什么强调组合?因为我见过太多团队只用一个。只开被动检查的,半夜流量低谷时后端挂了,到了早上才发现。只开主动检查的,health接口一切正常,实际业务早崩了。
核心总结:
- 健康检查是负载均衡器的“眼睛”,让你知道后端节点到底行不行
- 被动检查省资源但反应慢,适合附加监控
- 主动检查响应快但开销大,是主防线
- 组合使用 = 主动做快速发现 + 被动做真实验证
- 加密服务场景中,主动检查的TLS握手要与真实客户端一致
好,理解了健康检查是什么以及两种方式的区别,下一步我们就可以进入怎么配置、怎么选参数、怎么避免常见的坑了。