nginx不处理websocket会话同步,仅实现连接级粘滞;需通过ip_hash、sticky cookie或hash $http_sec_websocket_key确保同一连接始终路由至同一后端,并配合透传upgrade头、禁用缓冲、延长超时等配置,而状态共享与广播须由后端借助redis/kafka等实现。

Nginx 本身不处理 WebSocket 的会话同步,它只负责把连接稳定地转发到后端节点,并确保同一连接始终落在同一台服务器上——这是“会话粘滞”,不是“会话同步”。真正的状态共享、广播通知、跨节点消息分发,必须由后端服务自己实现。
会话粘滞是前提,不是同步
WebSocket 连接建立后,所有帧都走同一个 TCP 连接。如果 Nginx 把后续帧轮询到不同后端,目标节点没有该连接上下文,就会断连(如报错 1006)或静默丢消息。因此必须先做绑定:
- ip_hash:适合公网直连、IP 分布较散的场景;但 NAT 或 CDN 后客户端 IP 集中,容易负载不均
-
sticky cookie:后端在握手成功后 Set-Cookie(如
route=ws-02),Nginx 用sticky cookie route expires=1h path=/;路由;支持故障转移,更适配 Web 页面场景 - hash $http_sec_websocket_key:按每次握手唯一的 Sec-WebSocket-Key 哈希,保证单次连接内帧不漂移;但重连会生成新 key,不保证用户级连续性
同步靠后端,Nginx 不参与
Nginx 是无状态代理,不保存连接信息,也不转发消息。若需向全集群用户广播(比如群聊消息、系统通知),后端必须自行构建分发机制:
- 用 Redis Pub/Sub 或 Kafka 作为消息总线,各节点订阅并推送至本地连接
- 将在线连接映射存入 Redis(如
user:123 → ws://node2:8080/conn-789),广播时查表投递 - 引入轻量级网关层(如基于 OpenResty 的 Lua 脚本),在 Nginx 侧做简单路由判断,但核心状态仍由业务服务维护
配置必须协同生效,缺一不可
光有粘滞不够,若连接中途被 Nginx 主动断开,重连仍可能落到新节点。需同步保障:
- 透传升级头:
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" - 禁用缓冲:
proxy_buffering off和proxy_cache off放在具体location /ws/ { }块内 - 超时拉长:
proxy_read_timeout 86400(大于心跳间隔 3 倍以上)、proxy_send_timeout 86400 - 路径隔离:
location ^~ /ws/ { ... }避免被泛匹配 location 拦截,可加if ($http_upgrade != "websocket") { return 403; }校验
HTTPS 和高并发要额外注意
使用 wss 协议时,SSL 终止在 Nginx,仍需保持 proxy_http_version 1.1;同时确认 TLS 版本 ≥ TLSv1.2,避免握手失败。高并发下还需调大系统资源:
- 修改
/etc/security/limits.conf,提升文件描述符上限(如* soft nofile 1048576) - upstream 中启用
keepalive 32复用到后端的连接,降低建连开销 - 避免在 http 块全局设
proxy_buffering off,仅作用于 WebSocket location,防止干扰其他接口











