ip_hash 会因后端数量变化必然引发重分配,因其基于 hash(ip) % 当前服务器数计算路由;替代方案包括 cookie 会话保持、redis 管理 session、一致性哈希;必须使用时应禁用自动健康检查、采用“先加后删”策略并确保配置一致。

ip_hash 本身不是为“解决重分配”而设计的,它恰恰会因后端数量变化引发重分配。想在横向扩展时减少连接漂移,关键不是靠 ip_hash 配置技巧,而是要理解它的限制并绕开它。
ip_hash 的重分配是机制决定的,不是配置错误
ip_hash 使用 hash(IP) % 当前可用 server 数量 计算路由。只要 upstream 中 active server 数量一变(比如加一台、下线一台、某台健康检查失败),模运算的除数就变了,几乎所有 IP 的哈希结果都会跳转到新索引——这不是 bug,是设计使然。
- 3 台变 4 台:原来落到第 1 台的请求,可能全跑到第 3 台
- 有 server 被标记 down:即使只少 1 台,所有 IP 映射关系整体重排
- 哪怕只是临时抖动(如网络闪断触发 fail_timeout),也会触发批量迁移
真正能缓解扩展重分配的替代方案
如果你需要服务扩缩容时尽量保持客户端粘性,ip_hash 不适合直接用。更稳妥的做法是:
-
改用基于 Cookie 的会话保持:Nginx 的
hash $cookie_session_id consistent;或第三方模块如 sticky cookie,把 session ID 写入客户端,后端可共享或透传,扩容不影响已有连接 - 用 Redis 等外部存储管理 Session:后端无状态,任何节点都能处理任意请求,彻底消除对 IP 绑定的依赖
- 启用 consistent hash(一致性哈希):Nginx Plus 支持,开源版可通过第三方模块(如 nginx-sticky-module-ng)实现,增减节点只影响少量 key 的归属
如果必须坚持用 ip_hash,只能做有限控制
无法避免重分配,但可以降低其发生频率和影响范围:
- 关闭健康检查自动剔除(注释掉
check或health_check),改为人肉维护 active 列表 - 扩容时采用“先加后删”策略:新增 server 标记为
backup,观察稳定后再去掉 backup 并手动下线旧节点 - 确保所有 server 配置完全一致(不加
weight、max_fails等参数),否则 ip_hash 会被 Nginx 自动禁用 - 日志中加
$remote_addr $http_x_forwarded_for对比,确认你拿到的是真实用户 IP,而不是 CDN/SLB 的出口 IP
横向扩展时更推荐的默认策略
对大多数无状态服务,轮询或加权轮询 + 合理的健康检查,比强绑 IP 更健壮:
- 轮询天然适应节点增减,新增节点立即参与分担,老节点流量平滑下降
- 配合
max_fails=2 fail_timeout=15s,故障恢复快,不会长期卡在“半死”状态 - 如果真有状态需求,优先把状态外移到 Redis、数据库或客户端,而不是靠负载层绑定











