行情数据接入层剖析:协议选型、解码性能与多源合并

做市引擎的第一道关卡,就是行情接入。说白了,行情数据进不来,后面策略再牛也是白搭。我见过不少团队,策略模型跑得飞起,结果行情延迟一上来,全白干。今天咱们就聊聊行情接入层的三个核心问题:选什么协议、怎么解码快、多源数据怎么合并去重。

一、行情协议选型:FIX、FAST、WebSocket 怎么选?

我个人习惯,先看场景再选协议。别一上来就追求“最先进”,适合你的才是最好的。

协议 特点 适用场景 我踩过的坑
FIX 文本协议,可读性强,但带宽占用高 传统金融、机构间通信 解析慢,行情密集时CPU飙升
FAST 二进制压缩,带宽低,解码快 高频交易、低延迟场景 模板定义复杂,调试困难
WebSocket 全双工,基于帧,适合流式数据 数字货币、实时推送 重连逻辑没写好,丢数据

为什么会这样?FIX 是文本协议,每个字段都带标签和长度,解析起来自然慢。FAST 用了二进制编码和增量更新,带宽能省 70% 以上。WebSocket 呢,本质是 TCP 上的帧协议,适合做实时推送,但心跳和重连得自己处理。

我在项目中遇到过,某交易所强制用 FIX 协议,结果行情峰值时每秒 10 万笔,单机 CPU 直接打满。后来我们改用了 FAST,同样的数据量,CPU 占用降到了 30%。嗯,这里要注意,FAST 的模板定义一定要和交易所对齐,差一个字节都不行。

核心建议: 如果延迟要求 < 1ms,优先考虑 FAST;如果带宽有限,也选 FAST;如果只是做普通行情展示,WebSocket 足够了。

二、数据解码性能对比:谁更快?

解码性能直接决定了你能处理多少行情。我做过一个对比测试,结果如下:

协议 解码速度(万条/秒) 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

小技巧: 如果必须用 FIX,可以试试预编译模板。把字段偏移量提前算好,运行时直接按偏移量读取,能快 3 倍左右。

三、多源行情合并与去重策略

做市商通常接多个交易所的行情,一来做冗余,二来比价套利。但多源数据怎么合并?去重怎么做?这里我分享一套实战方案。

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,备交易所数据正常,但合并逻辑还在用主交易所的数据,导致策略报出错误价格。后来我们加了一个“延迟熔断”机制:如果主交易所延迟超过阈值,自动切换到备交易所。

警告: 多源合并时,一定要处理“数据乱序”问题。比如 A 交易所先发了第 100 笔,后发了第 99 笔。如果不做重排序,订单簿会乱掉。建议用优先级队列做缓冲,按序列号排序后再输出。

四、整体架构图

下面这张图展示了行情接入层的完整流程。从网络数据包到最终可用的行情数据,每一步都有优化空间。

行情接入层架构图 网络数据包 FIX / FAST / WebSocket 原始数据 协议解码层 零拷贝解码 / 预编译模板 / 对象池复用 多源合并与去重 时间戳对齐 / 序列号去重 / 延迟熔断 统一行情数据 内存队列 / 共享内存 / 零拷贝传递 策略引擎消费

从图里能看出来,每一层都有优化空间。我个人最看重的是第二层(协议解码)和第三层(多源合并),这两层做不好,后面全白搭。

实战建议: 先做性能基准测试,看看当前系统的瓶颈在哪。别一上来就优化解码,万一是网络带宽不够呢?用 perf 或火焰图分析一下,再动手。

好了,行情接入层的内容就聊到这。记住一句话:行情数据是做市引擎的血液,接入层就是血管。血管堵了,心脏再强也没用。


专注资料整理