WebSocket 断线重连:代理IP 出口切换后如何验证会话恢复
客户端显示已重连,用户却丢了消息或看到重复下单,是实时应用常见的假恢复。文章按客户端正常关闭、网络中断与服务端重启三类断线分别制造中断,比较恢复耗时、丢失与重复条数,再用消息序号、去重窗口和业务状态核对,确认恢复的是业务而不只是连接。
日志里出现"重连成功",并不代表业务恢复完成:消息可能缺失、重复处理或状态未同步。应按受控断线场景检查重连与业务状态,并根据协议契约验证恢复位置。本篇不预设断线一定发生在代理出口,也不把单一关闭码当作根因。
怎样判断连接恢复是否已经变成业务恢复
- 连接恢复:新的 WebSocket 完成握手,收到 101,可以收发消息。
- 业务恢复:断线期间产生的消息被补齐或明确丢弃,恢复后不重复、不乱序,业务状态与服务端一致。
连接恢复是必要条件,不是充分条件。客户端重连后如果没有带上恢复凭据,服务端可能按游标、时间窗或自身策略补发部分或全部消息,也可能直接拒绝恢复;策略不同,出问题的形态也不同:全量重放会重复,拒绝恢复会缺失。具体按哪种策略,以协议文档和测试结果为准。
如何分别制造三种可控断线
不同断线方式会触发不同的关闭码与恢复路径,必须分开测:
1. 客户端主动关闭:调用 close(1000),按应用预定策略验证停止或重新连接及状态处理;不自动重连不必然表示故障。
2. 网络层中断:在自建测试网络中丢弃连接、发送 RST 或停止客户端进程等,记录故障点和方向。若客户端报告 1006,将其视为本地未收到有效 Close 帧的异常状态,不预设所有中断都会触发该码。
3. 服务端主动断开:服务端关闭连接或重启,验证重连后的鉴权与恢复流程。
在自建测试环境中制造中断,不对正常业务链路注入故障。先做少量试跑检查测试流程,再根据业务 SLA、风险和观测波动确定正式覆盖次数。断线时机可覆盖空闲期、消息传输中和鉴权刚完成时,并记录 TCP RST、丢包、进程退出、心跳超时等实际证据。
网络层中断的定位可参考代理 IP 故障排查中心。
重连策略应该观察哪些指标
- 首次重连延迟:从检测到断线到发出重连请求的时间。
- 重连间隔序列:是否指数退避,是否带随机抖动。
- 重连次数上限:达到上限后是放弃还是降级。
- 鉴权是否重做:令牌过期时是否重新获取。
- 是否携带恢复凭据:resume token、最后一条消息的序号或事件 ID。
退避没有抖动时,大量客户端会在同一时刻重连,形成二次冲击。验证时观察间隔序列是否递增且带随机量。
常见的三种会话恢复机制怎么验证
- 服务端保留游标:客户端带上最后确认的序号,服务端从下一条开始推送。
- 客户端拉取历史:重连后主动请求断线时间窗内的消息,再切回实时流。
- 无状态重放:服务端按时间窗重放,客户端负责去重。
序号的单调范围可能限于某个分区、订阅或过滤条件;先确认序号作用域、客户端确认点、乱序窗口和过滤规则。三种机制按产品契约分别验证:游标是否被接受、历史拉取与实时流是否衔接、重放窗口是否被正确去重。缺少客户端 token 不代表服务端没有已保存的恢复位置。
如何检查补发消息是否重复或乱序
恢复阶段最容易出现"补多了"和"补乱了"。校验方法:
- 每条业务消息带唯一 ID 与单调递增序号。
- 客户端记录已处理 ID 的窗口,重复 ID 直接丢弃。
- 收到消息时按已确认的序号作用域检查连续性;出现缺口后,按协议选择缓冲等待、补拉历史或进入降级/重新同步,不规定所有系统都必须立即停止消费。
- 分别记录重复接收、去重后重复产生的业务副作用、最终缺失条数,作为恢复质量指标。
序号不能只靠时间戳,同一毫秒内的多条消息会无法排序。服务端生成序号时保证单调,客户端只做校验与去重。
如何确认重连后业务状态仍然一致
连接层和消息层都正常,业务仍可能不一致。核对三项:
1. 关键状态字段:账户余额、订单状态、会话归属是否与服务端一致。
2. 未确认操作:断线前发出但未收到确认的请求,重连后是否重发、是否被服务端去重。
3. 幂等性:重发的写操作是否只生效一次(去重机制见上一节)。
业务核对要读服务端的权威状态,不能只信客户端本地缓存。本地缓存与服务端不一致时,以服务端为准并记录差异。
如何记录恢复时间并完成验收
恢复时间要拆成两个数:断线到新连接可用,断线到业务补齐完成。前者反映重连策略,后者反映恢复机制。只报前者会低估用户实际等待时间。
- 断线类型:客户端 close(1000) | 恢复耗时:1.2 s | 丢失条数:0 | 重复条数:0 | 业务状态一致:是 | 证据:序号连续、状态字段一致
- 断线类型:网络中断(1006) | 恢复耗时:3.5 s | 丢失条数:0 | 重复条数:2 | 业务状态一致:是 | 证据:去重窗口命中、补齐完成
- 断线类型:服务端重启 | 恢复耗时:8.0 s | 丢失条数:0 | 重复条数:0 | 业务状态一致:是 | 证据:重新鉴权、游标续传
表中数值仅为示例,实际按测试记录填写;网络中断示例中的 1006 仅表示该次客户端本地观察到异常关闭状态,不代表确定的根因。重复接收不必然是缺陷,需进一步核对去重后的业务副作用。
验收表包含断线类型、恢复耗时、最终缺失条数、重复接收数、重复业务副作用、状态一致性和证据位置。覆盖次数与阈值按业务 SLA、风险和测量波动事先确定;3 次或 5 次只能作为试跑示例,不能当成通用充分门槛。正常 close(1000) 应按产品预定策略验证停止或恢复,不把不自动重连直接判错。任一关键证据缺失,结论应标注“证据不足”或“观察到重连成功”,不能写“恢复完成”。
测试工具的接入参数可对照代理设置帮助。
WebSocket 关闭状态和 Close 帧语义见 RFC 6455。
FAQ
Q:重连成功但消息少了一段,问题出在哪?
A:先对照客户端、服务端和网络事件确定可观测到的故障位置,再按协议检查恢复位置。恢复状态可能来自客户端凭据,也可能由服务端保存;没有客户端序号不能单独证明服务端无法续传。
Q:close code 1006 一定能复现吗?
A:不保证。1006 是本地报告的异常关闭状态,表示没有收到有效 Close 帧;不同客户端实现和故障方式下的观测结果可能不同,需记录具体故障注入和客户端事件。
Q:重复消息一定要在客户端去重吗?
A:取决于协议契约。服务端游标续传、时间窗重放和客户端去重的责任不同,应分别检查收到重复与重复业务副作用,不能只统计客户端收到的消息数。
