ip_hash本身不提供健康检查能力,需依赖max_fails/fail_timeout被动屏蔽或nginx_upstream_check_module主动探针;屏蔽期间请求直接失败而非重试,无法自动漂移,必须配合proxy_next_upstream等机制兜底。

在 Nginx 的 ip_hash 模式下,健康检查不能靠“自动漂移”来兜底——因为 IP 哈希本身是静态绑定的:同一个客户端 IP 固定打到同一台后端,即使那台后端已不可用,Nginx 也不会主动把它的请求重新哈希到其他节点。
ip_hash 本身不提供主动健康检查能力
Nginx 原生 ip_hash 指令只负责路由分发,不包含探测逻辑。它不会定期发探针、也不根据 HTTP 状态码判断后端是否存活。所谓“健康检查”,需要额外配置参数或模块来补足:
- max_fails + fail_timeout:这是最常用且原生支持的方式。它基于实际代理请求的失败次数做临时屏蔽
-
第三方模块(如 nginx_upstream_check_module):可实现独立于请求流的主动心跳检测,但需自行编译安装,且要确认与
ip_hash兼容 - 原生 keepalive 连接不影响 ip_hash 行为:长连接复用和哈希路由互不干扰,但也不能替代健康判断
推荐配置:用 max_fails 实现轻量级故障隔离
在 upstream 中为每台 server 显式加上失败容忍参数:
upstream backend_pool {
ip_hash;
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.103:8080 max_fails=3 fail_timeout=30s;
}含义是:某台服务器连续 3 次代理请求失败(如连接超时、502/504),Nginx 就会在接下来 30 秒内不再将新请求(包括该 IP 的后续请求)转发给它。注意:
- 屏蔽期间,原属于这台机器的客户端 IP 请求会直接返回 502 Bad Gateway,不会重试其他节点
- 这不是“负载再均衡”,而是“临时剔除”;恢复依赖后续请求的成功反馈
- 必须配合
proxy_next_upstream error timeout http_502;才能触发重试逻辑(但 ip_hash 下重试仍受限于哈希结果)
为什么不能依赖状态码做原生健康检查
Nginx 官方模块 ngx_http_upstream_module 不支持基于 HTTP 响应体或状态码的主动健康探测。比如你无法写:
# ❌ 这种语法 Nginx 原生不支持
health_check match=status_200;
match status_200 {
status 200;
}这类功能需要引入 Tengine 分支 或第三方模块 nginx_upstream_check_module。启用后可配置独立探针路径(如 /health),但要注意:
- 该模块的检查周期与请求流分离,适合监控,但不改变
ip_hash的路由决策逻辑 - 即便模块标记某节点为 down,
ip_hash也不会把已分配的 IP 流量自动迁移——除非你手动加backup节点承接 - IPv6 场景下,哈希仅取前 64 位,若业务对地址精度敏感,需验证一致性是否满足
辅助验证与可观测性建议
光配对还不够,得能确认行为是否符合预期:
- 在 log_format 中加入
$upstream_addr和$upstream_status,观察同一 IP 是否始终命中相同后端地址,以及失败时是否进入屏蔽期 - 用 curl 多次请求并记录响应头中的
X-Upstream(可自定义添加)或服务端日志,交叉比对路由稳定性 - 避免在 NAT 环境(如企业出口、运营商共享 IP)大规模使用 ip_hash,否则多个真实用户会被锁死到一台后端,造成严重倾斜


















