1. 性能基准与目标设定:为什么做市商需要极致性能?
做市商这行,说白了就是「抢跑」的生意。你比别人快1微秒,你就能吃到价差;慢1微秒,你就成了别人的流动性。我入行第一年带过一个团队,自研的做市引擎上线后,回测年化收益漂亮得不行。结果实盘第一天,直接亏了六位数。为什么?因为回测环境忽略了网络抖动和内核调度延迟。那笔教训让我明白一件事:没有性能基准的优化,都是耍流氓。
1.1 做市商为什么需要极致性能?
先问个问题:做市商赚的是什么钱?
不是方向性判断的钱,而是流动性提供者的风险溢价。你挂单在买一卖一,别人来吃单,你赚个价差。但这里有个致命问题——你的对手方是高频交易员和套利者。他们手里攥着FPGA和内核旁路技术,你的订单还没到交易所,他们的撤单指令已经落地了。
我见过最夸张的场景:某家做市商因为延迟高了200微秒,在某个热门币对上,连续三个月都是净亏损。后来一查,问题出在日志打印上——同步写日志把交易线程卡住了。嗯,这种坑,踩过一次就再也不敢犯了。
所以,极致性能不是炫技,是生存刚需。具体来说,延迟决定了你能不能抢到订单,吞吐量决定了你能同时做多少个品种,而抖动决定了你的策略是否稳定可靠。
1.2 核心指标:延迟、吞吐量、抖动
这三个指标,我习惯用「水管」来比喻:
- 延迟:水从水龙头流到杯子的时间。做市里就是订单发出到成交确认的耗时。
- 吞吐量:单位时间内能流过多少水。做市里就是每秒能处理多少笔订单。
- 抖动:水流速度忽快忽慢的程度。做市里就是延迟的方差。
你想想看,如果水管忽快忽慢(抖动大),你的做市策略根本没法做风控。我曾经有个项目,延迟均值只有5微秒,但P99.9延迟飙到了500微秒。结果就是,每1000笔订单里有一笔成交延迟极高,导致套利者抓住了这个窗口,把我们当提款机。
关键公式:
做市商盈亏 ≈ (价差收益) - (延迟成本 × 被套利次数) - (抖动惩罚 × 风控误报率)
延迟成本每降低10%,被套利次数可能下降30%以上。这是非线性收益。
1.3 如何定义延迟?从网卡到应用的全链路拆解
很多人一谈延迟,就只看「订单到交易所再回来」的RTT。这太粗糙了。我习惯把延迟拆成四段:
- 网络延迟:从你的服务器到交易所撮合引擎的物理距离。光速是极限,但实际受路由跳数和光纤质量影响。
- 内核延迟:数据包从网卡到用户态应用的时间。这里涉及中断处理、协议栈、socket缓冲区。
- 应用延迟:你的策略代码处理订单的时间。包括行情解析、信号计算、订单生成。
- 交易所延迟:交易所内部撮合、风控、回执生成的时间。这部分你控制不了,但可以测量。
我个人习惯用「染色包」技术来测量全链路延迟。就是在订单里嵌入一个时间戳,然后在回执里提取出来,计算差值。注意,时间戳必须用TSC寄存器或者HPET,不能用gettimeofday——那个精度太差了,误差本身就有几微秒。
避坑指南:
我曾经用std::chrono::high_resolution_clock来打时间戳,结果发现不同CPU核心之间的时钟不同步,测出来的延迟忽高忽低。后来改用__rdtsc()配合CPU频率校准,才拿到真实数据。记住:测量工具本身不能引入误差。
1.4 吞吐量:别只看峰值,要看持续能力
吞吐量指标,很多人喜欢报「峰值TPS 100万」。但做市商更关心的是持续吞吐量和有效吞吐量。
| 指标类型 | 定义 | 做市商关注点 |
|---|---|---|
| 峰值吞吐量 | 短时间内能处理的最大请求数 | 用于容量规划,但容易误导 |
| 持续吞吐量 | 长时间运行下的平均处理能力 | 决定了你能同时做多少个品种 |
| 有效吞吐量 | 剔除错误订单和超时订单后的成功处理量 | 直接关联实际收益 |
我见过一个团队,峰值TPS能做到50万,但持续跑10分钟后,因为内存碎片和GC问题,TPS掉到了5万。这种系统,你敢拿去做市吗?
所以,我建议在性能测试时,至少跑30分钟以上的稳定性压测,并且监控内存分配次数和GC暂停时间。如果用的是C++,注意检查tcmalloc或jemalloc的碎片率;如果是Python,嗯……建议别用Python做核心交易路径,除非你用了PyPy或者C扩展。
1.5 抖动:被忽视的隐形杀手
抖动,说白了就是延迟的「不稳定性」。做市策略通常假设延迟是稳定的,然后基于这个假设做报价和风控。一旦抖动出现,策略就会误判。
举个例子:你的策略设定「如果订单超过100微秒没成交,就撤单重发」。正常情况下,延迟在80-90微秒之间,策略运行良好。但某次因为内核调度,延迟突然跳到200微秒,策略就会误以为订单没成交,于是撤单重发。结果呢?原来的订单其实已经成交了,你又发了一笔,导致超买或超卖。这种错误,一次就能亏掉一周的利润。
注意:
抖动的主要来源包括:
- 内核上下文切换(特别是网络中断和定时器中断)
- CPU超线程竞争(同一个物理核心的两个逻辑核心互相干扰)
- 内存页错误(TLB miss导致的内存访问延迟飙升)
- NUMA跨节点访问(内存不在本地节点,延迟增加30%-50%)
解决方案:绑核、关闭超线程、使用大页内存、设置CPU亲和性。
1.6 设定合理的性能目标:SLO与SLA
目标不能拍脑袋。我习惯用「三个九」原则:
- 延迟SLO:P50延迟 < 10微秒,P99延迟 < 50微秒,P99.9延迟 < 200微秒
- 吞吐量SLO:持续吞吐量 > 10万笔/秒,且波动不超过20%
- 抖动SLO:延迟标准差 < 5微秒,且无超过500微秒的异常点
这些数字怎么来的?不是拍脑袋,而是基于你的交易品种和策略回测。比如你做的是BTC永续合约做市,盘口深度通常有几百个BTC,价差在0.01%左右。那么你的延迟只要不超过盘口更新频率(通常1-5毫秒),就能存活。但如果你做的是高频价差套利,延迟必须控制在10微秒以内。
我个人习惯先做「最坏情况分析」:假设所有不利条件同时发生(网络拥堵、CPU满载、内存带宽瓶颈),你的系统还能不能达到SLO?如果不行,那就得降级策略或者增加硬件冗余。
实战建议:
设定SLO时,留出30%的余量。比如你的硬件极限是5微秒,那就把SLO定在7微秒。为什么?因为生产环境总有你预料不到的干扰——隔壁团队的监控脚本、运维的定时任务、甚至机房的空调震动。这些因素,测试环境永远模拟不出来。
1.7 知识体系总览
下面这张图,是我做性能优化时常用的框架。它把「为什么优化」「优化什么」「优化到什么程度」串在了一起。
这张图的核心逻辑是:先明确「为什么」需要优化,再定义「优化什么」指标,接着解决「怎么测量」的问题,最后设定「优化到什么程度」的目标。后面的章节,我们会沿着这个框架,一步步深入每个环节。
我的个人习惯:
每次接手一个新系统,我都会先花一周时间做性能基准测试。不是跑几个脚本就完事,而是把延迟、吞吐量、抖动的分布图打印出来,贴在工位上。然后问自己三个问题:
- 这个系统的瓶颈在哪里?(网络?CPU?内存?IO?)
- 如果明天流量翻倍,系统还能撑住吗?
- 最坏情况下的延迟是多少?我能接受吗?
这三个问题,能帮你快速定位80%的性能问题。
好了,这一章的内容就到这里。记住:没有基准的优化是盲目的,没有目标的优化是无效的。下一章,我们会聊聊如何搭建一套低延迟的行情系统——那是做市商性能优化的第一道坎。
公众号:蓝海资料掘金营,微信deep3321