WebSocket集群Session粘滞本质是长连接被错误分发致状态丢失,解决关键是实现可靠可运维的连接级路由:ip_hash轻量但受IP真实性、IPv6偏斜和单点故障限制;Cookie粘滞更健壮,兼容代理且支持动态路由;Nginx需透传Upgrade头、禁用缓冲、延长超时;终极方案是无状态+消息总线(如Redis/Kafka)解耦连接与状态。

WebSocket 在集群中出现 Session 粘滞问题,本质是长连接被错误分发到不同后端节点,导致状态丢失、消息中断或心跳失败。解决的关键不是“要不要粘滞”,而是“用什么方式实现可靠、可运维的连接级路由”。
ip_hash:轻量但有硬约束
ip_hash 是最常用的入门方案,它基于客户端真实 IP 做哈希,确保同一 IP 的所有 WebSocket 帧(握手、ping、数据)始终落到同一台后端。
- 必须写在 upstream 块顶层,不能与 weight、backup、max_fails 共存,否则 Nginx 启动失败
- 依赖真实客户端 IP:前端若经过 CDN、WAF 或 NAT,需配合 real_ip_module 和 set_real_ip_from 还原 $remote_addr,否则所有请求哈希结果一致,变成单点打满
- IPv6 地址哈希易偏斜,/64 子网内大量地址可能映射到同一后端;企业内网或移动网络下共用出口 IP,也会造成连接集中
- 后端宕机时无自动重哈希,对应 IP 段的连接会持续失败,直到超时后才尝试下一节点
Cookie 粘滞:更健壮的推荐方案
相比 IP,用后端下发的 route Cookie 实现哈希路由,能规避 NAT、CDN、IPv6 等环境干扰,也支持连接重建后的路由一致性。
由 ReMe 驱动的记忆管理系统,支持跨会话记忆持久化、自动应用用户偏好以及智能上下文压缩...
- 后端在 WebSocket 握手成功后,通过 HTTP 响应头 Set-Cookie 写入唯一 route 标识(如 route=ws-node-2)
- Nginx 配置 hash $cookie_route; 或 sticky cookie=route expires=1h path=/;(需编译含 sticky 模块)
- 该方式不依赖网络拓扑,天然兼容各种前置代理,且 route 可按负载动态分配,比 IP 更可控
WebSocket 代理必须同步调优的参数
只配粘滞策略远远不够,Nginx 必须正确处理协议升级和长连接生命周期:
- 透传关键头:proxy_set_header Upgrade $http_upgrade; 和 proxy_set_header Connection "upgrade";(注意引号)
- 启用 HTTP/1.1:proxy_http_version 1.1;
- 禁用缓冲:proxy_buffering off;,防止帧被缓存或合并
- 延长超时:proxy_read_timeout 86400;(或更高),避免空闲连接被主动断开
真正解耦的终极方向:无状态 + 消息总线
如果业务已具备基础设施能力,建议跳出“粘滞”思维,转向无状态架构:
- 使用 Redis 或 Kafka 作为消息总线,各节点订阅/发布用户事件,消息不依赖连接所在节点
- 借助 SignalR(.NET)、STOMP + Spring Cloud Bus(Java)或自研广播机制,实现跨节点会话通知
- Session 数据统一存 Redis,连接建立、心跳、消息收发均查库/发消息,后端完全对等、可随时扩缩容










