3. 实时数据链路概览
在金融实时数据系统中,回放与补数并不是两个孤立功能,而是贯穿整条数据链路的“时间一致性能力”。要理解它们,必须先看清数据从交易所行情源到策略终端的完整路径。本节以端到端视角,拆解采集、传输、存储、计算、回放与补数六个环节的职责边界、关键组件与协作方式。
一、核心原理:六段链路与两类时间
实时数据链路可以抽象为六个连续阶段。采集层负责从交易所、行情商或内部系统获取原始报文;传输层负责低延迟、可追溯地把数据送达下游;存储层负责持久化并保留事件时间;计算层负责指标加工、聚合与信号生成;回放层负责按历史时间轴重放数据流;补数层负责在缺口发生后重新拉取并修复数据。
贯穿这六段的核心是两类时间:事件时间(数据在交易所实际发生的时刻)和处理时间(系统收到并处理该数据的时刻)。回放与补数之所以复杂,正是因为两者在实时链路中天然存在偏差。若存储层只记录处理时间,回放时就无法还原真实市场节奏;若补数时忽略事件时间,修复后的数据会与实时流产生错位。
二、方法流程:从采集到补数的协作机制
下面以一条典型的股票Level-2行情链路为例,说明各环节的协作流程。
- 采集:行情网关通过TCP/UDP接收交易所二进制报文,解析为标准化结构,并打上采集时间戳。常用组件包括C++行情网关、Python采集适配器。
- 传输:通过Kafka、Pulsar或Aeron等消息中间件传输。Kafka适合高吞吐与持久化,Aeron适合极低延迟场景。传输时需保证分区有序,通常以证券代码或频道作为分区键。
- 存储:原始报文写入对象存储或时序数据库,加工后数据写入ClickHouse、Doris或KDB+。存储层需同时保留事件时间与序列号,便于缺口检测。
- 计算:Flink、Spark Streaming或自研流计算引擎消费消息,生成快照、指标与信号。计算层需支持按事件时间窗口聚合,避免处理时间偏差。
- 回放:回放服务从存储层读取历史数据,按事件时间排序后重新注入消息队列或直接推送给策略。回放速度可调,支持倍速、暂停与跳转。
- 补数:当检测到序列号缺口或数据异常时,补数服务向行情商或交易所历史接口发起请求,拉取缺失区间,经校验后写回存储并触发下游重算。
# 典型缺口检测与补数触发逻辑(伪代码)
last_seq = redis.get("seq:600519")
current_seq = message.seq
if current_seq != last_seq + 1:
gap = (last_seq + 1, current_seq - 1)
补数任务队列.push({
"symbol": "600519",
"start": gap[0],
"end": gap[1],
"event_time_range": message.event_time
})
redis.set("seq:600519", current_seq)
三、案例场景:盘中缺口修复与盘后回放
假设某策略在盘中依赖逐笔成交数据。上午10:15,监控系统发现某只股票的逐笔序列号出现跳跃,缺失约200毫秒的数据。补数服务立即向行情商历史接口请求该区间数据,同时通知计算层暂停该股票的窗口聚合。补数数据到达后,先与前后序列号做连续性校验,再写回Kafka对应分区,计算层从缺口起点重新消费并修正指标。整个过程在秒级完成,策略无感知。
盘后回放场景则不同。研究员需要验证策略在历史某日的表现,回放服务从ClickHouse读取当日全部行情,按事件时间排序,以10倍速注入模拟撮合引擎。此时存储层中保留的事件时间成为回放节奏的唯一依据,任何处理时间偏差都不会影响回放结果。
四、关键组件清单与选型对比
不同环节对组件的要求差异明显。下表列出常见选型及其适用场景。
| 环节 | 关键组件 | 核心要求 | 典型选型 |
|---|---|---|---|
| 采集 | 行情网关、协议解析器 | 低延迟、高吞吐、协议兼容 | C++网关、Python适配器 |
| 传输 | 消息队列、流总线 | 有序、持久化、可重放 | Kafka、Pulsar、Aeron |
| 存储 | 时序库、对象存储 | 事件时间保留、高压缩比 | ClickHouse、KDB+、S3 |
| 计算 | 流计算引擎 | 事件时间窗口、Exactly-Once | Flink、Spark Streaming |
| 回放 | 回放服务、模拟撮合 | 倍速控制、事件时间排序 | 自研回放器、历史注入器 |
| 补数 | 缺口检测、历史拉取 | 自动触发、连续性校验 | 补数服务、对账任务 |
五、误区与复盘
误区一:只存处理时间,不存事件时间。回放时无法还原真实市场节奏,补数后数据与实时流错位。必须在采集入口就记录事件时间并贯穿全链路。
误区二:补数只补数据,不触发下游重算。缺失区间修复后,计算层若未重新消费,指标仍然错误。补数完成应发布重算事件。
误区三:回放与实时共用同一套消费逻辑,但忽略速度差异。回放可能以10倍速注入,若计算层未做背压或时间对齐,会产生大量乱序与重复。
复盘建议:定期对存储层做序列号连续性扫描,统计缺口分布;对补数任务记录耗时与成功率;对回放结果与实时结果做抽样比对,验证时间一致性。这三项检查能覆盖链路中大部分隐性故障。