websocket长连接在nginx负载均衡下断开的根本原因是http负载逻辑与长连接本质冲突;需透传upgrade/connection头、设超时为0、启用会话保持、禁用缓冲缓存。

负载均衡接入 WebSocket 长连接时断开,根本原因不是“配置漏了某一项”,而是传统 HTTP 负载均衡逻辑与 WebSocket 的长连接本质存在天然冲突。解决的关键在于:让 Nginx 不仅能完成协议升级,还要稳住连接、不切走、不静默关闭、不缓存帧——四点缺一不可。
必须透传 Upgrade 和 Connection 头
Nginx 默认不识别 Upgrade: websocket 请求头,也不会自动处理 Connection 升级逻辑。若缺失这两项,后端服务收不到握手请求,直接返回 400 或 502,客户端表现为“连接失败”或“瞬间断开”。
- proxy_set_header Upgrade $http_upgrade:把客户端原始的 Upgrade 头原样传给后端
- proxy_set_header Connection "upgrade":固定写死为 upgrade(注意引号),不能写 $http_connection,否则非 WebSocket 请求会误带 upgrade 值导致后端拒绝
- 建议配合 map 指令做安全兜底:map $http_upgrade $connection_upgrade { default upgrade; '' close; },再用 Connection $connection_upgrade,避免非 WebSocket 请求干扰
超时时间必须显式拉长,且设为 0 更稳妥
Nginx 默认 proxy_read_timeout 60s,这是 WebSocket 断连最隐蔽的元凶。空闲连接只要 60 秒没数据,Nginx 就静默关闭 TCP 连接,客户端无感知,直到下次发消息才报错。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- proxy_read_timeout 0:设为 0 表示永不因空闲超时关闭(推荐用于生产)
- proxy_send_timeout 0:同理,防止服务端发消息卡住时被中断
- proxy_connect_timeout 30s:保持合理,避免后端宕机时阻塞太久
- 注意:后端应用层心跳间隔(如 30s Ping)需小于 Nginx 的 read timeout,否则可能被中间设备先掐断
负载策略要绑定会话,不能轮询
WebSocket 连接建立后是状态化的,用户登录态、房间信息、未确认消息都存在内存里。如果 Nginx 轮询分发,第二次请求(比如重连)落到另一台机器,就会丢失上下文,表现就是“刚连上就断”“消息收不到”“重复登录”。
- 优先用 ip_hash:简单有效,适合公网 IP 稳定的场景
- IPv6 或 NAT 环境下 ip_hash 失效时,改用 hash $cookie_jsessionid; 或基于 token 的 sticky cookie 方案
- 避免用 least_conn:它只看连接数,不看连接归属;一个用户开 10 个 Tab,全挤在一台机器上,反而加剧不均
禁用缓冲和缓存,确保帧实时透传
WebSocket 是二进制/文本帧流,不是 HTTP 响应体。一旦开启 proxy_buffering,Nginx 可能攒多个帧一起发,造成延迟、粘包甚至连接卡死。
- proxy_buffering off:强制逐帧转发,零缓冲
- proxy_cache off:彻底禁用缓存模块,避免响应头被意外缓存
- proxy_http_version 1.1:必须显式声明,HTTP/1.0 不支持 keep-alive 和 upgrade










