ip_hash节点恢复后不会立即回切,需确保upstream配置完全一致(节点ip、端口、顺序)、已重载配置、无nat/代理干扰、未被fail_timeout标记,哈希结果才自然回归原节点。

当 Nginx 使用 ip_hash 负载均衡时,客户端 IP 会被哈希映射到固定后端节点。如果某个节点宕机被自动剔除,原属该节点的流量会临时分发到其他存活节点;而当该节点恢复后,Nginx **不会立即把原 IP 的请求切回**——因为 ip_hash 是无状态哈希,不记录“历史归属”,只要节点列表一致,哈希结果就固定。所谓“回切”,其实是哈希计算自然回归,但需满足前提条件。
确认 ip_hash 是否真的生效且节点已重新加入
这是最常被忽略的基础点:
- 检查 upstream 配置中,恢复的节点是否已去掉
down或backup标记,且未被max_fails/fail_timeout持续标记为不可用(可通过nginx -T输出确认当前生效配置) - 确保所有 worker 进程已重载配置(
nginx -s reload),否则旧进程仍按老 upstream 列表计算哈希 - 验证 upstream 中节点顺序是否变化 ——
ip_hash哈希结果依赖节点在 upstream 块中的**声明顺序**,增删节点或顺序调整会导致同一 IP 哈希到不同节点
观察哈希分布是否已自然回归
ip_hash 本身不“记忆”流量迁移,只做一致性哈希(基于 IP 和节点列表)。节点恢复后,只要 upstream 结构(IP+端口+顺序)与故障前完全一致,同一客户端 IP 的哈希值就会算回原节点。验证方法:
- 用固定客户端 IP(如 curl 指定 --interface 或从固定出口 IP 机器发起请求),连续访问并查看
upstream_addr日志字段,确认是否回到预期节点 - 注意:若客户端使用 NAT 或代理(如公司出口网关、CDN),真实 IP 可能被替换,导致哈希对象不是你认为的那个 IP
- 可在日志中添加
$remote_addr和$upstream_addr对照,确认哈希输入与输出是否符合预期
排查是否存在干扰机制
以下配置可能覆盖或破坏 ip_hash 的原始行为:
-
启用了 keepalive 连接复用:连接未断开前,后续请求仍走原连接,看似“没回切”,实则是连接池缓存。可临时关闭
keepalive或用新 TCP 连接测试 - 前端有 LVS/SLB 做了源 IP 透传但实际转发不一致:例如四层 SLB 后面挂多台 Nginx,各 Nginx upstream 配置不统一,导致哈希结果不一致
-
使用了 proxy_bind 或 real_ip 模块修改了 $remote_addr:比如
set_real_ip_from+real_ip_header配置错误,导致参与哈希的是内网地址而非客户端真实 IP
辅助诊断建议
快速定位问题根源:
- 开启 Nginx debug 日志(编译时需含
--with-debug),过滤ip_hash相关日志行,可看到具体哈希值和选中节点过程 - 写一个简单脚本,对目标 IP 执行多次请求(避免连接复用),统计
upstream_addr分布,对比节点恢复前后是否收敛 - 用
nginx -t和nginx -T确认运行中配置与预期一致,特别注意 upstream 块是否被 include 多次或存在隐藏覆盖











