nginx 的 ip_hash 对 ipv6 默认取前 64 位(8 字节)哈希,非完整 128 位;源码中 addr 指针虽指向全地址、长度设为 16,但循环仅读前 8 字节,导致同子网多终端映射同一后端。

Nginx 的 ip_hash 对 IPv6 地址默认使用完整 128 位地址参与哈希计算,但实际仅取前 64 位(即网络前缀部分)作为哈希输入——这是关键细节,很多配置出问题就卡在这里。
IPv6 哈希的实际行为
源码层面明确:IPv6 地址的哈希数据指针指向 sin6_addr.s6_addr,长度设为 16 字节(即 128 位),但 Nginx 在后续哈希运算中只读取前 64 位(前 8 字节)。这意味着:
- 同一子网内不同主机(如
2001:db8::1和2001:db8::2)很可能被映射到同一台后端服务器 - 若业务依赖客户端唯一性(如登录态绑定、限流计数),这种“前缀级哈希”可能导致多个用户被误判为同一来源
- 与 IPv4 的“前三字节”逻辑类似,本质是为减少哈希碰撞、提升映射稳定性,而非追求绝对唯一
如何验证当前是否按预期工作
不能只看配置是否写了 ip_hash,要抓真实日志确认:
- 在
http块中定义日志格式:log_format ipv6_hash '$remote_addr — $upstream_addr — $time_local'; - 确保 access_log 启用该格式,并用 IPv6 客户端(如 curl -6 或支持 IPv6 的浏览器)多次请求
- 观察相同 IPv6 前缀(如
2001:db8::/64)下的不同地址是否始终打到同一 upstream server
IPv6 场景下的注意事项
IPv6 环境下启用 ip_hash 需额外把关几个现实约束:
- 前端若经过代理或 CDN,必须用
real_ip_header X-Forwarded-For+set_real_ip_from正确还原原始 IPv6 地址,否则哈希的是代理 IP - 不建议在公网 IPv6 接入场景强依赖
ip_hash:因运营商常分配动态 /64 子网,用户换设备或重拨可能获得新地址,导致会话中断 - 若需更高精度哈希(比如基于完整 128 位),Nginx 开源版不支持;可改用
hash $remote_addr consistent;(需 1.7.2+),它对 IPv6 全地址做一致性哈希,扩容时影响更小











