websocket长连接平滑迁移需前后端协同:客户端通过服务发现获取地址、异常时指数退避重连;服务端共享会话状态至redis、主节点预通知切换;代理层禁用ip_hash、启用健康检查;心跳分网络与业务两级,结合rtt波动主动引导迁移。

WebSocket 在主备高可用架构中实现长连接的平滑迁移,核心不是“换服务器时不断开”,而是让客户端在感知不到服务切换的前提下,自动、安全、有序地接入新节点。这需要前后端协同设计,重点解决连接状态延续、会话上下文同步、故障切换时机控制三个问题。
客户端需具备智能路由与无感重连能力
前端不能硬编码单个 WebSocket 地址,而应通过动态服务发现获取接入点:
- 首次连接前,向统一网关(如 /api/ws/endpoint)发起 HTTP 请求,返回当前活跃的主节点地址(如 wss://ws-primary.example.com)及备用地址列表;
- 连接建立后,监听
onclose事件,但仅在event.code !== 1000(非主动关闭)且event.reason包含特定标识(如"failover")时触发迁移逻辑; - 重连时按优先级轮询地址列表,每次间隔采用指数退避(如 1s → 2s → 4s),并记录已尝试节点,避免反复打挂同一备用节点。
服务端需支持连接状态可迁移与会话亲和
主备节点之间必须共享关键会话元数据,否则用户重连后将丢失上下文:
- 用户连接成功后,服务端立即将
userId → channelId、订阅的 topic 列表、最后心跳时间等信息写入共享存储(如 Redis Cluster),TTL 设置为连接空闲超时时间 + 缓冲期(如 3 分钟); - 主节点异常下线前,若能预知(如收到 SIGTERM),应主动广播“即将切换”事件,并将未确认消息暂存至 Kafka 或 RocketMQ,供备用节点消费补推;
- 备用节点启动后,主动拉取共享存储中的活跃会话快照,对已存在但未心跳超时的连接,在客户端重连时直接恢复订阅关系,无需重新
subscribe指令。
代理层(Nginx / SLB)必须透传连接并维持会话粘性
主备切换常被卡在反向代理环节——它可能把重连请求又转回已宕机的主节点:
- Nginx 配置中禁用
ip_hash,改用基于 WebSocket 子协议或自定义 header 的 sticky session(例如识别Sec-WebSocket-Protocol: user-v2并绑定 upstream); - 设置
proxy_read_timeout 300、proxy_send_timeout 300,避免中间设备因空闲切断连接; - 启用健康检查:
health_check interval=3 fails=2 passes=2,确保备用节点就绪后再从 upstream pool 中剔除主节点,防止“脑裂”式流量分发。
心跳与熔断机制要区分网络层与业务层故障
简单 ping/pong 不足以判断是否该切换节点——可能是临时抖动,也可能是节点整体失联:
- 客户端同时维护两级心跳:底层每 30s 发
ping,服务端必须响应pong;应用层每 60s 发{"type":"status","seq":123},服务端需回执并校验seq连续性; - 连续 2 次底层心跳失败 → 触发本地重连倒计时;连续 3 次应用层 status 无响应或乱序 → 上报监控并启动主备切换流程;
- 服务端对每个连接记录最近 5 次心跳 RTT,若标准差 > 200ms 且均值突增 3 倍,主动推送
{"type":"suggest_failover", "target":"wss://ws-standby.example.com"},引导客户端定向迁移。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











