ip_hash在NAT环境下必然导致局域网用户集中到同一后端,因出口IP相同;需确认$remote_addr重复性、验证真实IP还原、检查ip_hash是否生效,并根据场景改用consistent hash或least_conn等策略。

局域网内用户流量全打到一台后端,不是 ip_hash 配置错了,而是它在 NAT 环境下的必然表现。ip_hash 把整个局域网出口 IP 当作“一个客户端”来处理,自然全部哈希到同一台服务器——这不是故障,是设计使然。排查重点不在修算法,而在确认现象成因、验证真实 IP、评估是否该换策略。
确认是不是局域网出口 IP 导致的假性不均
企业、校园、运营商宽带用户通常共用一个公网出口 IP(如 203.101.5.8 或 114.240.128.x)。只要 access log 中 $remote_addr 大量重复,且 $upstream_addr 始终指向同一台后端,基本可锁定是 NAT 引起的集中映射。
- 在 log_format 中加入 $remote_addr - $upstream_addr 字段,快速观察日志模式
- 用命令统计高频 IP 和对应后端:
awk '{print $1, $NF}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10 - 若前几行都是同一 $remote_addr 对应同一 $upstream_addr,说明不是配置问题,而是输入数据失真
检查真实客户端 IP 是否被正确还原
如果前端有 CDN、WAF、SLB 或云防火墙,Nginx 收到的 $remote_addr 很可能是中间设备的内网地址(如 10.0.1.5),而非用户真实 IP。此时 ip_hash 实际是在对几个固定代理 IP 做哈希,加剧倾斜。
- 对比日志中 $remote_addr 和 $http_x_forwarded_for:若前者是内网段(10.x、172.16–31.x、192.168.x),后者含公网 IP,则需启用 real_ip 模块
- 确保配置了 set_real_ip_from(指定可信上游网段)和 real_ip_header X-Forwarded-For
- 注意 real_ip_recursive on 必须开启,才能从多层代理头中提取最左端真实 IP
验证 ip_hash 是否真的在生效
不能只看 upstream 块写了 ip_hash,要从请求结果反推它是否实际运行。
- 用固定 IP 的终端(如某台测试机或手机热点)连续发 10+ 请求,观察日志中 $upstream_addr 是否始终不变
- 若返回多个不同后端,可能原因包括:某 server 被健康检查标记为 down、max_fails 触发临时剔除、配置未 reload 生效
- 注意 ip_hash 不兼容 backup、weight、max_fails 等参数;只要 upstream 中任意 server 行带这些字段,ip_hash 会静默失效,退化为轮询
判断是否该放弃 ip_hash 改用更合适的方案
ip_hash 的目标是会话稳定,不是负载均衡公平性。当发现大量局域网用户被绑死在单台机器上,且已确认 IP 还原无误,就说明它不适合当前场景。
- 改用 hash $remote_addr consistent:节点增减时仅局部重映射,比 ip_hash 抗抖动能力强得多
- 需要更高区分度,可组合字段:hash "$remote_addr$http_user_agent" consistent
- 登录类接口必须保持会话?优先用 sticky cookie(需 nginx-plus)或基于 Redis 的共享 Session,彻底解耦粘性与 IP
- 若服务本身无状态(JWT 鉴权 + 外部 Session 存储),直接切 least_conn 或加权轮询,天然更均匀


















