TL;DR
- 别用“定时全量快照 JSON 广播”硬怼深度流:带宽爆炸 + 客户端渲染崩 + 数据陈旧。
- 正确姿势是 Snapshot(基准快照) + Diff(增量更新):把成本从 O(N) 降到 O(K)。
- 为一致性必须引入 Sequence Number:客户端发现序列号不连续就触发重同步,否则状态会永久污染。
- 工程优化重点:推绝对量而不是 delta、短窗口批处理、多级深度聚合、必要时上二进制协议。
1. 问题为什么会爆:全量快照推送的三宗罪
- 网络带宽爆炸:100 档深度快照 5–10KB,10Hz × 1 万订阅 = 约 1GB/s 级别的出向带宽(还没算 TLS/WebSocket 额外开销)。
- 客户端性能瓶颈:频繁 JSON 反序列化 + 全量重绘,导致 UI 卡顿、发热、耗电。
- 无效更新/数据陈旧:两次快照之间往往只变了少数价位,但你每次都把 99% 的重复数据发出去。
2. 核心范式:Snapshot + Diff(增量更新)
把客户端订单簿当作服务器订单簿的一个副本(Replica)。
第一次给客户端一份快照(Snapshot)作为基准;之后只推送发生变化的价位(Diff/Updates)。
这样网络与客户端计算成本从“深度档位数 N”变成“本次变化档位数 K”。
关键建议:Diff 里推绝对数量(最新总量),而不是“变化量”。绝对量是幂等的,鲁棒性更强。
3. 一致性保障:序列号(Sequence)与重同步(Resync)
增量更新引入了“丢包/断线”风险。解决方法是给每个快照与每个增量更新打上严格递增的序列号。
客户端每次收到更新,校验 prevSequence == localSequence:
如果不连续,立即丢弃本地状态并重新请求快照(重同步),避免错误状态持续扩散。
4. 推荐架构:撮合事件 → 深度聚合 → 推送网关
- 撮合引擎:唯一真相源,输出原子事件(下单/撤单/成交)。
- 事件总线:保证有序消费(通常按交易对分区)。
- 深度聚合服务(有状态):重建完整订单簿,生成 Snapshot/Diff,并维护 Sequence。
- 推送网关(无状态):维护海量 WebSocket 连接,按订阅关系扇出(fan-out)。
5. 性能优化抓手(落地清单)
- 短窗口批处理:10–50ms 合并多个价位变更,减少小包与协议开销(延迟换吞吐)。
- 多级深度聚合:按精度/档位分层(例如 0.1/1.0 价格粒度),让“普通用户”订阅更轻的流。
- 二进制协议:当 JSON 成为瓶颈,用 Protobuf/MessagePack 或自定义定长结构压缩 50%+。
- 无状态网关:网关挂了就重连 + resync;状态都在聚合服务与序列号机制里。