nginx 自带的 max_fails + fail_timeout 仅是被动容错,非主动健康检查;真正的心跳检测需依赖 nginx_upstream_check_module 模块,通过定期 http/tcp 探活实现主动发现后端状态。

Nginx 自带不支持真正的主动心跳检测,必须靠第三方模块(如 nginx_upstream_check_module)才能实现定期 HTTP/TCP 探活;仅靠 max_fails + fail_timeout 是被动容错,不是健康检查。
为什么 max_fails 和 fail_timeout 不算健康检查
它们只在请求真正发出去并失败后才起作用——也就是说,Nginx 仍会把第一个请求打到已宕机的后端,等超时或收到 502/504 后才标记为不可用。这会导致:
- 首请求必然失败,用户感知明显(比如白屏、超时)
- 故障发现延迟 =
fail_timeout值(常见设为 10s~30s),期间所有新请求仍可能被轮询到坏节点 - 无法区分“服务暂时忙”和“进程已死”,纯靠错误响应计数
所以它本质是「故障兜底」,不是「主动探活」。
怎么用 nginx_upstream_check_module 做真实心跳检测
这个模块由淘宝团队开发,已适配主流 Nginx 版本(如 1.20.x、1.22.x),需重新编译 Nginx 加载。关键点:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 先确认你当前 Nginx 版本:
nginx -v,再选对应 patch(例如 1.20.x 用check_1.20.1+.patch) - patch 必须在 Nginx 源码目录执行:
patch -p1 ,否则编译报错 -
check指令必须写在upstream块内,且只能出现一次;多个参数要写在同一行或换行加反斜杠 - HTTP 类型检查依赖后端能响应一个轻量 endpoint(如
/health),返回 2xx 或 3xx 才算成功
典型配置示例:
upstream backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
check interval=3000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "GET /health HTTP/1.1\r\nHost: example.com\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
如何验证心跳是否生效并查看状态
模块自带 check_status 指令,但必须显式暴露一个 location 才能访问:
- 在
http块里加:check_status;(默认路径是/status) - 或者自定义路径:
location /healthz { check_status html; },支持html、csv、json格式 - 访问该地址时,如果看到表格中某节点的
Status列显示up或down,且Rise/Fall计数在变化,说明心跳正在运行 - 注意:该页面无认证,生产环境务必配合
allow/deny限制 IP,或走内网访问
容易被忽略的兼容性与运维细节
编译加载模块后,几个硬伤常导致心跳静默失效:
- Nginx 配置语法检查通过(
nginx -t)≠ 模块已加载成功;要用nginx -V 2>&1 | grep -o check确认输出含nginx_upstream_check_module - 后端服务开了防火墙?
check请求默认走 80/443,若后端监听非标端口(如 9884),必须在server行明确写出端口,且确保该端口对 Nginx 所在机器可达 -
check_http_send中的Host头必须匹配后端实际接受的域名,否则可能被拒绝或路由到默认 vhost 返回 404 - 如果后端是 Spring Boot,默认
/actuator/health返回 JSON,但check_http_expect_alive只校验状态码,不校验 body,所以只要 HTTP 状态是 200 就算通过
真正上线前,建议手动模拟一次 curl -v http://backend-ip:port/health,确认响应头、状态码、耗时都符合预期——心跳检测再准,也救不了一个连不通的 endpoint。










