应使用 consistent_hash 模块替代 ip_hash 实现会话绑定,优先基于 $cookie_session_id 哈希,无 Cookie 时降级为 "$remote_addr:$http_user_agent" 组合指纹,并配合共享 Session 存储与生命周期对齐。

直接用 ip_hash 做会话绑定看似简单,但在真实生产环境里容易出问题——比如用户走的是 NAT 网关、运营商地址池共享、或手机网络频繁切换 IP,都会导致会话中断。更稳的做法是用 consistent_hash 模块,按客户端标识做一致性哈希,既保持会话粘性,又具备节点增减时的平滑迁移能力。
确认 Nginx 已编译支持 consistent_hash 模块
该模块非官方内置,需确认是否已安装。执行以下命令检查:
-
nginx -V 2>&1 | grep -o 'consistent_hash'—— 若有输出说明已支持 - 若无输出,需重新编译 Nginx 并添加 ngx_http_consistent_hash 模块,或使用 OpenResty(默认集成)
选择稳定的哈希键:优先用 Cookie,次选用 $remote_addr + $http_user_agent 组合
单纯依赖 $remote_addr 和 ip_hash 一样脆弱。推荐以下两种生产级写法:
-
带登录态的 Web 应用:用自定义会话 Cookie,例如
consistent_hash $cookie_session_id;,前提是后端在用户登录后统一写入该 Cookie(如 Spring Session 或自研 Token) -
无登录态或 Cookie 不可控场景:组合客户端指纹,例如
set $hash_key "$remote_addr:$http_user_agent"; consistent_hash $hash_key;,能显著降低哈希碰撞率,比单用 IP 更稳定
upstream 配置示例(含健康检查与容错)
下面是一个已在高并发 MinIO + Grafana 混合集群中验证的配置片段:
upstream backend_cluster {
consistent_hash $cookie_grafana_session; # 优先绑定 Grafana 用户会话
# fallback: 若无该 cookie,则用组合指纹兜底
# set $fallback_key "$remote_addr:$http_user_agent";
# consistent_hash $fallback_key;
<pre class="brush:php;toolbar:false;">server node-a.example.com:3000 weight=1 max_fails=2 fail_timeout=15s;
server node-b.example.com:3000 weight=1 max_fails=2 fail_timeout=15s;
server node-c.example.com:3000 weight=1 max_fails=2 fail_timeout=15s;
# 启用主动健康检查(需 nginx_upstream_check_module)
check interval=3 rise=2 fall=3 timeout=10 type=http;
check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
注意:consistent_hash 必须独占一行,不能和 ip_hash、hash 等其他 hash 类指令共存;每个 server 行不能加 backup 或 down 标记,否则一致性逻辑失效。
配合后端做好会话生命周期对齐
一致性哈希只管请求路由,不解决会话数据本身是否一致。必须同步做到:
- 所有后端节点共享同一套分布式 Session 存储(如 Redis),避免仅靠路由“假装”会话存在
- Cookie 的
Max-Age和后端 Session 过期时间严格一致,防止前端带着过期 Cookie 被持续打到同一台节点却拿不到数据 - 首次无 Cookie 请求,后端应生成并 Set-Cookie 返回,确保后续请求可被哈希识别











