行情数据接入层剖析:协议选型、解码性能与多源合并
做市引擎的第一道关卡,就是行情接入。说白了,行情数据进不来,后面策略再牛也是白搭。我见过不少团队,策略模型跑得飞起,结果行情延迟一上来,全白干。今天咱们就聊聊行情接入层的三个核心问题:选什么协议、怎么解码快、多源数据怎么合并去重。
一、行情协议选型:FIX、FAST、WebSocket 怎么选?
我个人习惯,先看场景再选协议。别一上来就追求“最先进”,适合你的才是最好的。
| 协议 | 特点 | 适用场景 | 我踩过的坑 |
|---|---|---|---|
| FIX | 文本协议,可读性强,但带宽占用高 | 传统金融、机构间通信 | 解析慢,行情密集时CPU飙升 |
| FAST | 二进制压缩,带宽低,解码快 | 高频交易、低延迟场景 | 模板定义复杂,调试困难 |
| WebSocket | 全双工,基于帧,适合流式数据 | 数字货币、实时推送 | 重连逻辑没写好,丢数据 |
为什么会这样?FIX 是文本协议,每个字段都带标签和长度,解析起来自然慢。FAST 用了二进制编码和增量更新,带宽能省 70% 以上。WebSocket 呢,本质是 TCP 上的帧协议,适合做实时推送,但心跳和重连得自己处理。
我在项目中遇到过,某交易所强制用 FIX 协议,结果行情峰值时每秒 10 万笔,单机 CPU 直接打满。后来我们改用了 FAST,同样的数据量,CPU 占用降到了 30%。嗯,这里要注意,FAST 的模板定义一定要和交易所对齐,差一个字节都不行。
二、数据解码性能对比:谁更快?
解码性能直接决定了你能处理多少行情。我做过一个对比测试,结果如下:
| 协议 | 解码速度(万条/秒) | CPU 占用 | 内存分配 |
|---|---|---|---|
| FIX(原生解析) | 8 | 高 | 大量 |
| FIX(预编译模板) | 25 | 中 | 中等 |
| FAST(标准解码) | 60 | 低 | 少量 |
| FAST(零拷贝优化) | 120 | 极低 | 几乎无 |
| WebSocket(JSON) | 15 | 中 | 大量 |
| WebSocket(Protobuf) | 50 | 低 | 中等 |
你想想看,FAST 零拷贝优化比 FIX 原生解析快了 15 倍。怎么做到的?说白了,就是避免内存复制。传统解码要先把数据从网络缓冲区拷到应用缓冲区,再解析。零拷贝直接操作网络缓冲区,省掉了中间步骤。
我曾经踩过一个坑:用 Java 做 FAST 解码,默认的 ByteBuffer 分配方式导致大量 GC。后来改成直接内存 + 对象池,GC 暂停从 50ms 降到了 1ms 以下。避坑指南:解码性能瓶颈往往不在 CPU,而在内存分配和 GC。
三、多源行情合并与去重策略
做市商通常接多个交易所的行情,一来做冗余,二来比价套利。但多源数据怎么合并?去重怎么做?这里我分享一套实战方案。
3.1 时间戳对齐
不同交易所的时间戳精度不一样,有的到毫秒,有的到微秒。我建议统一转成纳秒,用同一个时钟源(比如 NTP 同步后的系统时钟)做基准。否则,同一个订单簿的快照,A 交易所说 10:00:00.123,B 交易所说 10:00:00.124,你信谁?
3.2 去重策略
去重不是简单删掉重复数据。我见过有人用哈希表去重,结果内存爆了。正确的做法是:
- 基于序列号去重: 每个行情消息都有唯一序列号,按序列号递增接收,跳过的就是重复或丢失的。
- 基于时间窗口去重: 设定一个 100ms 的窗口,窗口内相同价格、相同数量的订单视为重复,只保留第一条。
- 基于内容哈希去重: 对消息内容做 MD5 或 CRC,相同哈希的直接丢弃。注意,哈希碰撞概率极低,但理论上存在。
我个人习惯用序列号 + 时间窗口的组合策略。序列号保证顺序,时间窗口过滤高频重复。嗯,这里要注意,时间窗口不能设太大,否则会丢失真正的更新。
3.3 合并逻辑
多源合并的核心是“谁先到用谁”,但也要考虑数据质量。我建议给每个交易所一个权重,比如:
- 主交易所:权重 1.0,数据优先采用
- 备交易所:权重 0.8,数据延迟超过 5ms 则丢弃
- 辅助交易所:权重 0.5,仅用于校验
我曾经遇到一个情况:主交易所行情突然延迟 100ms,备交易所数据正常,但合并逻辑还在用主交易所的数据,导致策略报出错误价格。后来我们加了一个“延迟熔断”机制:如果主交易所延迟超过阈值,自动切换到备交易所。
四、整体架构图
下面这张图展示了行情接入层的完整流程。从网络数据包到最终可用的行情数据,每一步都有优化空间。
从图里能看出来,每一层都有优化空间。我个人最看重的是第二层(协议解码)和第三层(多源合并),这两层做不好,后面全白搭。
好了,行情接入层的内容就聊到这。记住一句话:行情数据是做市引擎的血液,接入层就是血管。血管堵了,心脏再强也没用。