ip_hash无法自动漂移是因为其静态哈希机制使同一ip永远绑定固定后端,宕机后不重新计算哈希,也不主动摘除节点;需用sticky cookie或consistent_hash配合健康检查与proxy_next_upstream实现故障转移。

在 Nginx 中,ip_hash 本身不支持自动健康检查和节点漂移——它只是根据客户端 IP 做哈希后固定调度到某台后端,即使该后端宕机,Nginx 默认仍会尝试转发(除非配置了 proxy_next_upstream),但不会重新哈希选新节点,也就无法实现“会话节点自动漂移”。真正能实现带健康检查的会话保持+故障转移,需组合使用:upstream 的健康检查机制 + 会话保持替代方案(如 sticky cookie 或 consistent_hash) + proxy_next_upstream 规则。
为什么 ip_hash 无法自动漂移?
ip_hash 是静态映射:同一 IP 永远落在同一个 upstream server 上,Nginx 不会因该 server 失败而重新计算哈希换节点。即使 server 被标记为 down,Nginx 也不会把已哈希绑定的请求“迁移”到其他节点——这违背了 ip_hash 的设计初衷(保证会话粘性),但也导致其缺乏弹性容错能力。
- 宕机后,请求持续失败,直到手动剔除或超时重试(默认不重试非 5xx 错误)
- 没有内置心跳、主动探活、自动摘除/恢复逻辑
- 无法与
max_fails/fail_timeout协同触发“漂移”
推荐方案:用 sticky cookie + 主动健康检查
替代 ip_hash,改用基于 Cookie 的会话保持(Nginx Plus 支持,开源版需借助 nginx-sticky-module 或升级到 1.25.3+ 内置的 sticky 指令),配合主动健康检查,可实现“首次分配 + 故障时重分配 + 自动恢复后回归”:
- 启用主动健康检查(仅限 Nginx Plus 或使用
nginx-upstream-check-module编译的开源版) - 配置
sticky cookie srv_id expires=1h domain=.example.com path=/;(开源版 1.25.3+) - 设置
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;,让失败请求可被重发 - 搭配
proxy_next_upstream_tries 3;和proxy_next_upstream_timeout 10s;控制重试行为
开源版实用折中:consistent_hash + 被动健康检查
若无法引入第三方模块或升级,可用 hash $cookie_srv_id consistent;(需客户端携带标识)或 hash $remote_addr consistent; 替代 ip_hash,再结合被动健康检查:
- 在 upstream 中启用
max_fails=3 fail_timeout=30s; - 配合
proxy_next_upstream让失败请求跳过异常节点 - consistent hash 在节点增减时比 ip_hash 更平滑,部分请求会自然“漂移”到新节点
- 注意:首次请求无 cookie 时需后端写入,或由 Nginx 用
add_header Set-Cookie "srv_id=...";注入(需 Lua 或 map 模块辅助)
关键配置示例(开源版 + 被动检查)
upstream backend {
hash $remote_addr consistent;
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
}
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 5s;
}
此配置下,当某节点连续失败 3 次,30 秒内不再选它;请求失败后最多重试 1 次(共 2 次尝试),总超时 5 秒。由于使用 consistent hash,$remote_addr 映射可能在节点不可用时落到另一台——即实现了有限条件下的“自动漂移”。











