ip_hash通过客户端IP哈希实现购物车会话保持,确保同一用户请求始终路由至同一服务器,避免轮询导致的状态不一致;但需配置real_ip_module透传真实IP、规避NAT倾斜、禁用weight、搭配健康检查,并逐步演进至Redis或一致性哈希方案。

电商购物车依赖用户私有状态,若用默认轮询,请求分散到不同后端,购物车就容易“加了又没、删了还在”。ip_hash 是一种轻量级粘性路由方案,它让同一客户端 IP 的请求始终打到同一台应用服务器,从而避免状态丢失。但它不是开箱即用的银弹,必须针对性优化才能稳定支撑购物车场景。
确保真实客户端 IP 可被正确识别
CDN、WAF、四层代理或公司内网 NAT 都会让 $remote_addr 变成中间节点地址,所有用户被哈希到同一台后端,ip_hash 彻底失效。
- 在 http 块启用 real_ip_module,并声明可信代理段:set_real_ip_from 192.168.0.0/16; set_real_ip_from 10.0.0.0/8; set_real_ip_from 172.16.0.0/12;
- 指定真实 IP 来源头:real_ip_header X-Forwarded-For;
- 在 proxy_pass 所在 location 中透传原始信息:proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- 验证方式:在后端日志或 access_log 中加入 $realip_remote_addr 或 $upstream_addr 字段,确认记录的是用户公网 IP,而非 10.x 或 192.168.x 地址
规避 ip_hash 固有缺陷带来的倾斜与漂移
IPv4 默认只取前三个字节哈希(如 192.168.1.100 和 192.168.1.254 视为相同),NAT 环境下大量用户挤在同一后端;节点增删或顺序调整会触发全量重哈希,导致大批用户购物车“瞬间清空”。
- 上游 server 列表禁止混用 weight 参数——否则 Nginx 启动失败;如需权重调度,应改用 hash $cookie_session_id consistent 等替代方案
- 扩容时优先新增节点并保持原有节点顺序,避免重排引发集体漂移
- 临时下线节点前,先用 down 标记,观察日志中对应 IP 是否平稳迁移,再真正摘除
- 对高价值用户(如登录态 user_id 已知),可考虑 OpenResty + lua 拓展,按 $arg_user_id 或 $http_x_user_id 做自定义 hash,比 IP 更精准
搭配基础健康检查与可观测性补位
ip_hash 本身不提供故障转移智能性。某台后端宕机时,对应 IP 段请求会直接 502,用户购物车操作中断。
- 为每个 server 添加健康探测:server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
- 在 access_log 中固定记录 $upstream_addr $upstream_response_time,便于快速定位某 IP 是否长期落在异常节点或频繁跳变
- 设置监控项:统计单位时间内同一 IP 对应的 upstream_addr 变化频次,突增即告警,提示可能遭遇 NAT 变更或代理异常
明确演进路径,避免长期依赖
ip_hash 是过渡手段,不是终局解。当业务增长、移动端占比升高、或出现大规模 NAT 场景时,它会越来越不可靠。
- 短期:用 Redis 统一存储购物车,前端携带 token 或 user_id,后端无状态,彻底解除对路由粘性的依赖
- 中期:改用一致性哈希(如 ketama),节点变更仅影响小部分映射关系,降低漂移规模
- 长期:将设备指纹(device_id)或登录态标识注入请求头,Nginx 层基于该字段做 hash,比 IP 更稳定、更隐私友好











