ip_hash启用需满足三大前提:真实客户端ip可达、后端列表稳定、网络无大规模ip复用;且必须顶格置于upstream首行,仅支持纯ip:port格式的至少两台后端,不兼容weight等参数。

直接在 upstream 块第一行写 ip_hash; 就能启用,但真正起作用的关键不在这一行,而在它依赖的三个前提:真实客户端 IP 必须可得、后端列表必须稳定、网络环境不能大量复用 IP。
基础配置必须严格满足的硬性条件
ip_hash 不是“加了就生效”的开关,而是有明确语法和结构约束:
- 必须放在 upstream 块最开头,顶格书写,不能缩进,也不能和其它 hash 指令(如 hash $cookie_jsessionid)共存
- upstream 内至少要定义两台后端服务器,只写一个 server(比如 localhost 或单节点)会导致 Nginx 启动失败或行为异常
-
server 行只能写 IP:PORT,不能带 http://、路径或协议前缀,例如
server 10.0.1.10:8080;正确,server http://10.0.1.10:8080/错误 - 不支持 weight、backup、down 等参数,加上会导致配置校验失败,Nginx 无法启动
必须还原真实客户端 IP,否则全白配
如果请求经过 CDN、WAF、前置 Nginx 或云 LB,$remote_addr 默认是上一跳地址,所有用户会被哈希到同一台后端——看起来“会话保持”了,其实是假象。
正确做法分两步:
- 在
http块中声明可信代理网段和真实 IP 头字段:set_real_ip_from 192.168.0.0/16;<br> set_real_ip_from 10.0.0.0/8;<br> real_ip_header X-Forwarded-For;
- 在
location中透传头信息:proxy_set_header X-Real-IP $remote_addr;<br> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
避开常见失效场景
即使配置全对,以下情况仍会导致会话漂移或负载倾斜:
- IPv4 只取前三段做哈希:192.168.1.100 和 192.168.1.200 被视为同一 IP,在 NAT 环境(如企业内网、校园网、4G/5G 共享出口)下极易集中打到一台后端
- 后端数量或顺序变动会整体重哈希:新增一台 server、临时下线一台、甚至只是调整 server 行顺序,所有已有 IP 的映射都会偏移,大量用户 session 断连
- 某台 server 标记为 down 时,剩余节点承接流量,但原有 IP 映射关系仍在剩余节点上维持——这点看似合理,但扩容恢复后不会自动回填,需手动 reload 配置才能重建平衡
更可靠的替代方案建议
当业务增长、出现频繁扩缩容、或用户大量来自 NAT 网络时,应考虑升级策略:
-
改用 Cookie 哈希:在 upstream 中写
hash $cookie_JSESSIONID consistent;,天然规避 IP 复用问题,且支持权重 -
后端统一接入 Redis 存储 Session:如 Spring Boot 配置
spring.session.store-type=redis,彻底解耦路由与状态,无需任何 Nginx 会话保持逻辑 -
TCP/UDP 四层场景必须换 stream 模块:ip_hash 在 stream 块中不生效,需改用
hash $remote_addr consistent;











