ip_hash在企业内网多用户同出口时负载严重倾斜,因NAT使所有请求的$remote_addr变为同一出口IP,哈希结果始终指向单台后端;需用real_ip_module还原真实内网IP,或改用cookie/token/一致性哈希,并必须实现Redis等集中式Session共享。

ip_hash 在企业内网多用户同出口环境下容易出现严重负载倾斜,根本原因是大量终端共享同一个公网出口 IP(如 NAT 网关、防火墙或统一出口路由器),Nginx 对该出口 IP 哈希后始终映射到同一台后端服务器,导致其他服务器空闲、单点过载甚至服务不可用。
为什么同出口 IP 会让 ip_hash 失效
ip_hash 默认使用 $remote_addr,而内网用户经过 NAT 或代理后,真实客户端 IP 已被替换为出口设备的 IP。例如:500 名员工通过一台 192.168.10.1 的防火墙访问系统,Nginx 收到的全是 192.168.10.1 —— 所有请求哈希结果一致,100% 落到 upstream 中某一台 server 上。
这不是配置错误,而是机制局限:ip_hash 本就无法区分同一源 IP 下的多个真实用户。
临时缓解:启用 real_ip_module 并还原真实内网 IP
若出口设备支持透传原始 IP(如通过 X-Forwarded-For 或自定义头),可配合 Nginx real_ip_module 还原:
- 在 http 或 stream 块中配置 set_real_ip_from 指定可信代理段(如内网网关 IP 或网段)
- 用 real_ip_header X-Forwarded-For 或对应字段提取最左/最右真实 IP(注意防伪造,建议搭配 real_ip_recursive on)
- 确保 upstream 块中 ip_hash 仍生效——此时哈希源变为还原后的内网地址(如 172.16.5.123),而非出口 IP
⚠️ 前提是出口设备确实携带并正确填充了原始 IP,且网络路径中无多层不可信代理污染头信息。
更可靠的替代方案:改用一致性哈希或业务标识哈希
当 IP 不具备区分度时,应放弃基于 IP 的绑定逻辑,转向更稳定的会话锚点:
- hash $cookie_JSESSIONID:适用于 Java 应用已生成有效 session ID 的场景,只要 cookie 未过期,哈希结果稳定
- hash $arg_token 或 hash $http_authorization:对接口级鉴权系统(如 JWT)更友好,token 或 bearer token 具备天然唯一性
- consistent_hash $binary_remote_addr(需升级至较新 Nginx 版本):相比普通 ip_hash,一致性哈希在增减后端时仅影响少量连接,适合动态扩缩容
这些方式不依赖网络拓扑,对 NAT、移动切换、DHCP 地址变更等场景鲁棒性更强。
长期必须补足 Session 共享能力
ip_hash 只是“请求钉住”,不是“状态共享”。一旦目标服务器宕机或发布重启,用户会话立即丢失。真正解法是让所有后端能读写同一份 Session:
- 接入 Redis 集群作为集中式 Session 存储(推荐 Redis Cluster 或哨兵模式)
- Java 应用启用 Spring Session + Redis;PHP 启用 redis session handler;.NET 使用 IDistributedCache
- 配合 sticky session(如 ip_hash)降级为可选策略,仅用于缓存加速,不作为可用性依赖
没有共享 Session,任何负载均衡算法都只是在掩盖架构缺陷。

















