WebSocket集群中session不能内存共享,因各节点JVM隔离;Redis仅存用户ID→节点映射等轻量元数据,不存不可序列化的Session对象;消息靠Pub/Sub路由,需规避订阅延迟、无持久化等坑。

前端多实例 WebSocket 同步不是靠“让前端自己同步”,而是靠后端集群统一管理连接归属 + 可靠路由消息 —— 否则必然出现“只推到部分实例、用户收不到”。
WebSocket 集群里 session 为什么不能靠内存共享
每个 Spring Boot 实例的 WebSocketSession 默认存在 JVM 堆里,节点之间不互通。用户 A 连到 node1,node2 根本不知道这个 session 存在;你调用 session.getBasicRemote().sendText() 时,如果误在 node2 上执行,就会抛 IllegalStateException: The session has been closed 或静默失败。
- Redis 不是用来存 session 对象本身(序列化复杂、反序列化风险高),而是存映射关系:比如
user:1001 → node1或session:abc123 → node2 - 别直接把
WebSocketSession放进 Redis —— 它不可序列化,且含 Socket 引用,跨 JVM 失效 - 真正要存的是轻量元数据:用户 ID、会话 ID、绑定的节点 host:port、最后活跃时间
用 Redis Pub/Sub 转发消息时必须绕开的三个坑
Pub/Sub 是最轻量的节点通信方式,但容易因使用不当导致消息丢失或重复:
- 订阅者必须在应用启动后立即完成订阅,不能等到第一次收到消息才 init —— 否则启动窗口期的消息全丢
- 不要在
@OnOpen里做耗时操作(如查 DB、远程调用),否则会阻塞握手线程,Nginx 触发502 Bad Gateway - Pub/Sub 没有持久化,如果某节点临时下线再上线,期间广播的消息它就收不到 —— 关键业务需搭配 Redis Stream 或 Kafka 补偿
前端重连时如何避免重复登录和消息乱序
用户网络抖动触发前端 socket.close() → 自动重连,这时后端必须识别这是“同一会话续接”,而不是新连接:
- 客户端首次连接带 token 或
clientId参数(如wss://api.example.com/ws?token=xxx),服务端解析后存入 Redis:client:xxx → node1 - 重连请求携带相同
clientId,后端先查 Redis:若已存在且对应节点还存活,直接复用旧 session;否则清理旧记录、新建绑定 - 服务端推送消息前加单调递增的
seq字段,前端按序号去重/缓冲,防止因重连导致消息倒灌
nginx 配置 WebSocket 代理时最容易漏掉的 header
没配对的 Upgrade 和 Connection header 是 80% 的“连接建立失败”根源:
- 必须写全这两行:
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; -
$http_upgrade是 nginx 内置变量,值为websocket(小写);硬写成"WebSocket"会导致握手失败 - 如果后端是 wss(HTTPS over WS),nginx 必须终止 SSL,并确保
proxy_pass http://backend指向的是 HTTP 内网地址,不能写成https://
真正难的不是“怎么转发消息”,而是“怎么让所有节点对‘谁连在哪’达成瞬时一致”——Redis 的过期时间、节点心跳检测频率、重连窗口内的状态补偿,这些细节一旦松动,就会在高并发时暴露为偶发性收不到消息。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











