ip_hash可实现基于客户端IP的会话保持,通过对IPv4前三个字节或完整IPv6地址哈希并取模,将同一IP请求固定转发至同一后端;但存在节点变更导致漂移、NAT下负载倾斜、不兼容weight等限制。

使用 Nginx 的 ip_hash 指令可以实现客户端 IP 与后端服务器的“绑定”,即同一客户端请求始终被转发到同一台后端节点。这在需要会话保持(session stickiness)但又不依赖外部 session 存储的场景中很实用,比如老旧应用未做无状态改造、或短时内需保证请求顺序。
ip_hash 的基本用法和原理
ip_hash 是 Nginx 内置的负载均衡算法之一,工作在 upstream 块中。它对客户端 IPv4 地址的前三个字节(如 192.168.1.100)或整个 IPv6 地址做哈希运算,再对后端服务器数量取模,从而固定分配目标服务器。
注意:它只基于源 IP,不识别真实用户(例如多用户共用 NAT 出口时,所有用户会被视为同一个客户端);也不感知 Cookie 或 TLS 信息。
配置示例:
upstream backend {
ip_hash;
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
只要 upstream 中服务器列表不变,哈希结果就稳定——新增/删除节点会改变映射关系,导致部分客户端“漂移”。
ip_hash 的限制与常见问题
- 不支持动态扩缩容:增减后端节点会打乱原有哈希分布,已连接客户端可能被重定向到新机器,造成会话中断。
-
IPv4 和 IPv6 处理不同:IPv4 默认取前三段哈希(防内网地址波动),IPv6 使用完整地址。若混合部署,需确认客户端地址是否被正确透传(如经过 CDN 或代理时,
$remote_addr可能是代理 IP)。 -
无法绕过哈希强制转发:即使某台后端异常,
ip_hash默认不会自动踢出该节点(除非显式配置down或max_fails+fail_timeout),可能导致请求持续失败。 - 不适用于移动网络或大企业出口:一个公网 IP 后可能有成百上千用户,容易造成后端负载倾斜。
增强稳定性的实用建议
-
配合健康检查使用:为每个
server行添加max_fails=3 fail_timeout=30s,让 Nginx 自动临时屏蔽不可用节点,减少手动干预。 -
确保真实客户端 IP 可见:如果上游有 LVS、云负载均衡或 CDN,需开启
proxy_protocol或在 header 中传递X-Forwarded-For,并在 Nginx 中用set_real_ip_from+real_ip_header还原真实 IP。 -
避免与 weight 混用:
ip_hash不兼容weight参数(Nginx 会忽略 weight),如需权重调度,应改用hash $remote_addr consistent;(需商业版或较新开源版支持一致性哈希)。 - 测试哈希分布是否均匀:可用脚本模拟一批不同 C 段 IP 请求,观察各后端访问量比例,确认无明显倾斜(尤其当后端数量非 2 的幂时)。
替代方案简要对比
若 ip_hash 无法满足需求,可考虑:
-
hash 指令 + cookie:用
hash $cookie_session_id实现更精准的用户级绑定(需后端写入 cookie)。 - sticky 模块(商业版):支持基于 cookie 的粘性会话,支持 fallback 和优雅剔除。
- 外部会话共享:如 Redis 存储 session,后端服务无状态,彻底摆脱绑定依赖。
ip_hash 简单有效,适合轻量、可控、IP 分布较分散的内部或小规模业务场景。用好它的关键是理解其边界,并提前应对 IP 复用和节点变更带来的影响。










