3. 补录通道建立与验证

逐笔数据丢包后的补录,本质上是一次“用旁路通道把缺失的成交明细重新取回并落库”的受控操作。它与实时行情订阅走的是两条不同的链路:实时链路追求低延迟、允许少量丢失;补录链路追求完整性与可核对性,允许慢,但不允许“看起来成功、实际缺数”。因此本节的核心不是写一个能跑的请求,而是把通道建对、把参数配对、把请求构准、把响应验透。

一、补录接口选型:先看数据源能力,再看业务约束

补录接口通常有三类可选形态,选型时按“数据源是否提供、时间粒度是否满足、单次返回上限是否够用”三个条件依次过滤。

  • 按时间区间查询的明细接口:入参为起始时间、结束时间、证券代码或市场代码,返回区间内全部逐笔成交。适合补几分钟到几小时的缺口,是最常用的形态。缺点是单次返回条数常有上限(例如单次最多 5000 条),缺口大时需要分段。
  • 按序号/流水号续传的增量接口:入参为起始序号,返回该序号之后的连续记录。适合已知缺口起止序号、且数据源保证序号连续的场景,补录精度最高,能天然避免“按时间查重或漏边”的问题。
  • 文件回补/落地文件下载:数据源按分钟或按日生成落地文件,通过文件服务下载后本地解析入库。适合大缺口(如整段行情中断数十分钟)或接口查询受限的场景,但存在文件生成延迟,不适合分钟级即时补录。

选型的判断顺序建议是:若缺口可用序号精确定位且数据源支持续传,优先选增量接口;若只能按时间定位,选区间明细接口并做好分段;若缺口超过单次查询上限一个数量级以上,改用文件回补更稳妥。需要特别注意的是,部分数据源的区间接口对“结束时间”是开区间,对“起始时间”是闭区间,边界记录会落在区间外,这一点必须在选型阶段就确认清楚,否则补录完成后仍会残留一条边界缺失。

二、连接参数配置:把“能连上”变成“连得对”

连接参数不只是地址和端口。补录通道的可靠性取决于一组相互约束的参数,配置时建议逐项确认并记录在案。

参数类别典型参数配置要点
接入地址补录服务主机、端口、备用节点主备地址都要配,避免单节点故障时补录中断
身份认证账号、令牌、签名密钥令牌有效期要覆盖整个补录窗口,长缺口补录前先刷新
会话控制连接超时、读超时、重试次数读超时应大于单次最大返回耗时的估计值,重试要幂等
流量控制单次返回上限、请求间隔、并发数并发不宜过高,避免触发数据源限流导致部分分段失败
数据约定时间格式、时区、编码、字段版本时区必须与数据源一致,字段版本要与本地解析器匹配

一个常见的坑是时间参数。假设本地系统使用北京时间,而补录接口要求 UTC 时间戳,若直接把本地时间字符串传过去,会整体偏移 8 小时,补回来的数据“有记录但全错位”。配置阶段应固定一条规则:所有时间参数在发出前统一转换为接口约定的时区与格式,并在日志中同时打印原始时间与转换后时间,便于事后核对。

三、补录请求构造:分段、去重与幂等

请求构造的关键是把一个大缺口拆成若干可独立成功、可独立重试的小段。以区间明细接口为例,假设缺口为 09:45:00 至 10:12:00,单次返回上限 5000 条,而该时段成交密集,每分钟约 1200 条,则单段覆盖时间不宜超过 4 分钟。可以按 3 分钟一段切分,得到 9 段请求,每段独立记录请求参数、返回条数、首末记录时间与序号。

请求示例(区间明细接口,参数为教学示例)
POST /api/v1/trades/query
{
  "market": "SH",
  "symbol": "600XXX",
  "start_time": "2024-06-03T01:45:00Z",   // 对应北京时间 09:45:00
  "end_time":   "2024-06-03T01:48:00Z",
  "fields": ["seq", "trade_time", "price", "volume", "direction", "trade_id"],
  "page_size": 5000,
  "request_id": "bk-20240603-600XXX-001"
}

构造时有三条硬约束。第一,分段边界要重叠一条记录:上一段的结束时间与下一段的起始时间留一条记录的余量,落库时按 trade_id 或 seq 去重,宁可重复不可漏边。第二,request_id 必须唯一且可追溯,建议由“补录批次号+证券代码+段序号”组成,重试时复用同一 request_id,便于数据源侧识别幂等请求。第三,字段列表显式声明,不要依赖默认返回字段,否则数据源升级后字段增减会直接导致解析失败。

四、响应校验:从“返回成功”到“数据可信”

响应校验分四层,逐层通过才算补录成功。

  1. 传输层:HTTP 状态码、业务返回码、错误信息。注意区分“无数据”和“查询失败”,前者返回空列表且业务码为成功,后者业务码非零,二者绝不能混为一谈。
  2. 结构层:返回条数是否等于声明条数、字段是否齐全、时间与价格能否按约定格式解析、seq 是否单调递增。
  3. 完整性层:本段首条记录时间是否覆盖上一段末条之后、末条记录是否到达本段结束边界、相邻段之间 seq 是否连续无跳号。若发现跳号,说明该段实际未取全,需要缩小时间窗重取。
  4. 一致性层:抽样比对补录数据与实时链路同期缓存(若有)的成交价、成交量、方向是否一致;核对补录后本地逐笔表的记录总数与数据源声明的区间总数是否吻合。
补录最常见的“假成功”是:接口返回成功、条数也非零,但因分段边界处理不当,缺口两端各少一条记录。这类问题在总量核对时往往只差一两条,极易被忽略,必须依靠 seq 连续性和边界时间双重校验才能发现。
补录通道:选型 → 连接 → 请求分段 → 四层校验 接口选型 区间明细接口 序号续传接口 落地文件回补 连接参数 主备地址 / 端口 令牌有效期覆盖窗口 读超时 > 单次耗时 时区统一为 UTC 字段版本匹配解析器 并发与限流约束 请求构造 按上限切分时间窗 边界重叠一条记录 request_id 唯一幂等 显式声明返回字段 逐段记录首末 seq 响应校验 ① 传输层 ② 结构层 ③ 完整性层 ④ 一致性层 缺口分段与边界校验(示例:09:45:00–10:12:00,按 3 分钟切分) 段1 09:45–09:48 段2 09:48–09:51 段3 09:51–09:54 … 中间段 段8 10:06–10:09 段9 10:09–10:12 橙色括号:相邻段重叠一条记录 落库按 trade_id / seq 去重 通过条件 seq 连续无跳号 · 首末时间覆盖边界 总条数与数据源声明一致 异常处置 跳号 → 缩小时间窗重取该段 边界缺失 → 调整开闭区间后补取

五、一次完整补录的操作闭环

把上述四步串起来,一次可复现的补录操作大致如下(参数为教学示例,非实测结果):确认缺口为 09:45:00–10:12:00,共 27 分钟;数据源支持区间明细接口,单次上限 5000 条,估算每分钟约 1200 条,故按 3 分钟切分为 9 段;连接参数中读超时设为 15 秒、重试 2 次、request_id 前缀为 bk-20240603-600XXX;逐段发送并落库,每段落库后立即校验 seq 连续性;全部完成后核对总条数,若与数据源声明的区间总数一致、且首末记录时间覆盖 09:45:00 与 10:12:00,则判定补录成功。若某段出现跳号,只重取该段,不影响其他已成功分段。

建议把每次补录的批次号、分段参数、每段返回条数、首末 seq、校验结论记录成一张补录台账。丢包补录往往不是一次性的,台账能让下一次同类缺口补录直接复用已验证的参数组合,也能在事后追查“某条成交为何缺失”时快速定位到具体分段。

最后强调一点:补录通道的验证标准不是“接口返回 200”,而是“补录后的逐笔表在缺口区间内 seq 连续、时间覆盖完整、总量吻合”。只有这三项同时成立,补录才算真正完成,否则只是把一次丢包换成了另一次不易察觉的缺数。