处理行情源的缺口与延迟
目标
区分行情源捕获中真正丢失的数据与延迟到达的数据;通过 A/B 仲裁区分可补齐的数据与真正的缺口;使用百分位数度量延迟,定位尾部集中区间;并能够为不同区间确定恢复方式。
为什么重要
行情源建立在既不保证顺序也不保证到达的传输之上,因此接收方必须根据序号进行判断。如果判断方式错误,问题不会悄无声息地过去,而会堵塞线路。若按到达顺序统计缺口,结果会比实际值高出五倍以上;按这个数量请求重传,又会增加请求流量并加剧延迟,延迟进一步增加乱序,使缺口看起来更多。
本练习强制执行的四点都是实际现场规则。缺口按集合判断——晚到不等于丢失,仅凭到达顺序无法区分两者。请求重传前先查看另一个通道——这正是部署冗余的原因,无需请求即可补齐的比例占绝大多数。通过尾部观察延迟——平均值会把两个世界混合成一个数字。将计算方式写入文件——百分位数定义不同,同一数据就会得出不同结论,从此讨论的不再是数据,而是定义。
本次捕获覆盖 2026-08-27 开盘后约 11 分钟。交易所发送的原始数据从序号 1 到 12000,没有缺口;我们通过 A、B 两个通道接收。两个通道都发生了丢包,并且在开盘后不久以及 09:08 左右出现了显著的延迟峰值。
百分位数按如下方式计算——最近秩法。将值按升序排列后,取第 idx = ceil(p * n / 100) 个值(从 1 开始计数)。使用 Python 整数时为 lat[(p*n + 99)//100 - 1]。平均值用总和除以数量后向下取整。延迟分析仅以通道 A 为对象;如果同一个 seq 到达多次,只使用最先到达的一条。
步骤
- 创建
/root/cap/feed,原样运行答案中的生成器,生成/root/cap/feed/feed.jsonl。若更改随机种子,结果将与评分值不符。 - 在
/root/cap/feed/shape.txt中写七行:lines=、ch_a_lines=、ch_b_lines=、ch_a_unique=、ch_b_unique=、ch_a_dup=、seq_max=。 - 在
/root/cap/feed/gaps.txt中写入arrival_jumps_a=、missing_a=、missing_b=、gap_runs_a=;将通道 A 未收到的序号按连续区间分组,写入/root/cap/feed/gaps_a.csv,表头为from_seq,to_seq,count。 - 在
/root/cap/feed/arb.txt中写入recoverable_from_b=、true_holes=、hole_runs=;将两个通道都未收到的区间写入/root/cap/feed/holes.csv,格式为from_seq,to_seq,count。 - 在
/root/cap/feed/latency.txt中写入method=nearest_rank以及n=、p50_us=、p95_us=、p99_us=、max_us=、mean_us=。 - 按
ts_send所在分钟分桶,在/root/cap/feed/tail.csv中写入minute,n,mean_us,p99_us,over_10ms,并在/root/cap/feed/tail.txt中写入worst_minute=、worst_p99_us=、over_10ms_total=、burst_minutes=。minute是以 09:00 为 0 的整数,burst_minutes则用逗号连接平均值超过 10ms 的分钟。 - 针对每个真正的缺口区间,在
/root/cap/feed/retx.csv中写入from_seq,to_seq,count,action。连续 5 个以上时使用snapshot,少于 5 个时使用retransmit。在/root/cap/feed/retx.txt中写入retransmit_runs=、retransmit_seqs=、snapshot_runs=、snapshot_seqs=。 - 在
/root/cap/feed/report.md中编写报告。需要## 무슨 일이 있었나、## 갭、## 지연、## 돈으로 얼마인가、## 무엇을 고쳐야 하나五个章节。
参考
- 时间精确到微秒。通过字符串切片读取,可以避免经过浮点数,因此更安全。
- 本次捕获的分钟桶从 0 到 10,共 11 个。
- 常见错误 1:第 3 步按文件中的到达顺序扫描并统计缺口。该数字不是重传请求的对象数量。
- 常见错误 2:第 5 步不去除重复项。如果连因重传而到达两次的记录也计入,分布会发生偏移。
- 常见错误 3:第 6 步将通道 B 也混入统计。两个通道的路径不同,延迟分布也不同。
创建 A/B 冗余行情源捕获
创建 /root/cap/feed,原样运行答案中的生成器,生成 /root/cap/feed/feed.jsonl。若更改随机种子,结果将与评分值不符。
原样运行生成器即可。若更改随机种子,结果将与评分值不符。
统计各通道的接收数量和重复项
在 /root/cap/feed/shape.txt 中写七行:lines=、ch_a_lines=、ch_b_lines=、ch_a_unique=、ch_b_unique=、ch_a_dup=、seq_max=。
分别统计各通道的行数和不同 seq 的数量。如果两个数字不同,其差值就是重复数量。
区分丢失与延迟到达
在 /root/cap/feed/gaps.txt 中写入 arrival_jumps_a=、missing_a=、missing_b=、gap_runs_a=;将通道 A 未收到的序号按连续区间分组,写入 /root/cap/feed/gaps_a.csv,表头为 from_seq,to_seq,count。
使用两种方式统计:一是按到达顺序读取,统计 seq 跳跃幅度大于 1 的位置;二是统计 1..12000 中该通道一次也未收到的序号。
使用通道 B 补齐,只留下真正缺口
在 /root/cap/feed/arb.txt 中写入 recoverable_from_b=、true_holes=、hole_runs=;将两个通道都未收到的区间写入 /root/cap/feed/holes.csv,格式为 from_seq,to_seq,count。
从通道 A 未收到的序号集合中减去通道 B 已收到的序号,就是真正的缺口。再将这些序号按连续区间分组。
计算延迟百分位数
在 /root/cap/feed/latency.txt 中写入 method=nearest_rank 以及 n=、p50_us=、p95_us=、p99_us=、max_us=、mean_us=。
仅使用通道 A,并且每个 seq 只取最先到达的一条。百分位数采用最近秩法——升序排列后取第 ceil(p*n/100) 个值。平均值使用整数除法向下取整。
定位尾部集中的区间
按 ts_send 所在分钟分桶,在 /root/cap/feed/tail.csv 中写入 minute,n,mean_us,p99_us,over_10ms,并在 /root/cap/feed/tail.txt 中写入 worst_minute=、worst_p99_us=、over_10ms_total=、burst_minutes=。minute 是以 09:00 为 0 的整数,burst_minutes 则用逗号连接平均值超过 10ms 的分钟。
按 ts_send 所在分钟分桶,分别计算每个桶的数量、平均值、p99 和超过 10ms 的数量。平均值超过 10ms 的分钟即为 burst。
区分重传与快照
针对每个真正的缺口区间,在 /root/cap/feed/retx.csv 中写入 from_seq,to_seq,count,action。连续 5 个以上时使用 snapshot,少于 5 个时使用 retransmit。在 /root/cap/feed/retx.txt 中写入 retransmit_runs=、retransmit_seqs=、snapshot_runs=、snapshot_seqs=。
按长度划分第 4 步得到的真正缺口区间。连续 5 个以上时使用 snapshot,少于 5 个时使用 retransmit。
编写行情源质量报告
在 /root/cap/feed/report.md 中编写报告。需要 ## 무슨 일이 있었나、## 갭、## 지연、## 돈으로 얼마인가、## 무엇을 고쳐야 하나 五个章节。
需要五个章节。延迟章节必须包含 p99;措施章节则要说明要更改缺口判断方式、监控指标和去重中的哪一项。