1. 性能基准与目标设定:定义延迟、吞吐量、抖动等核心指标,设定SLA目标

做量化交易系统,第一件事不是写代码,而是搞清楚一个问题:你到底要优化什么?

我见过太多团队,上来就怼着某个指标猛干,结果上线后发现瓶颈根本不在这。说白了,没有基准,就没有方向。没有目标,优化就是瞎忙活。

这一章,我们先把「尺子」造出来。你得知道量什么,怎么量,量到多少才算合格。

1.1 核心指标:延迟、吞吐量、抖动

交易系统里,我们最关心的就三个指标。嗯,其实所有高性能系统都差不多,但交易场景对它们的要求格外苛刻。

1.1.1 延迟(Latency)

延迟就是「从事件发生到系统响应」的时间差。在交易里,这个事件可能是行情数据到达,也可能是订单提交。

我个人习惯把延迟拆成三部分来看:

  • 网络延迟:数据在网线上跑的时间。这个基本由物理距离决定,光速是上限。
  • 处理延迟:CPU 在计算、解码、校验上花的时间。这是咱们能优化的主战场。
  • 排队延迟:数据在队列里等着被处理的时间。很多人忽略这个,其实它往往是最大的坑。

关键认知: 延迟不是平均值,而是百分位值。P50(中位数)好看没用,P99.9 才是用户真实体验。做交易,我们甚至看 P99.999。

我在项目中遇到过一件事:某个策略回测时平均延迟只有 5 微秒,团队高兴得不行。结果一上实盘,频繁出现 200 微秒的尖峰。查到最后,是 GC 暂停导致的。你看,只看平均值,你永远不知道系统什么时候会「卡一下」。

1.1.2 吞吐量(Throughput)

吞吐量是单位时间内系统能处理多少笔交易或多少条行情。说白了,就是「系统有多能扛」。

延迟和吞吐量其实是跷跷板关系。你想想看,一味追求低延迟,可能会限制并发处理能力;反过来,拼命压榨吞吐量,延迟必然上升。

我建议用 Little's Law 来理解这个关系:

L = λ × W

其中 L 是系统中平均请求数,λ 是吞吐量,W 是平均延迟。这个公式告诉我们:在系统容量固定的情况下,吞吐量和延迟是绑定的。

场景 典型吞吐量要求 说明
高频做市 10万+ 订单/秒 极低延迟优先,吞吐量靠硬件堆
中频套利 1万-5万 订单/秒 延迟和吞吐量需要平衡
低频策略 100-1000 订单/秒 吞吐量通常不是瓶颈

1.1.3 抖动(Jitter)

抖动是延迟的「波动程度」。为什么单独拿出来说?因为对于交易系统,稳定的低延迟比偶尔极低的延迟更重要。

举个例子:

  • 系统 A:延迟稳定在 10 微秒,几乎没有波动。
  • 系统 B:平均延迟 8 微秒,但有时会跳到 100 微秒。

你选哪个?我肯定选 A。因为交易策略依赖的是「确定性」。你不知道那 100 微秒的抖动什么时候来,但你知道它来了就会让你丢单。

避坑指南: 我曾经在一个项目里花了三周优化平均延迟,从 12 微秒降到了 6 微秒。结果上线后,抖动从 2 微秒飙到了 15 微秒。策略直接崩了。后来我才明白,消除抖动比降低延迟更重要。从那以后,我的优化目标里永远把「抖动」放在第一位。

1.2 设定 SLA 目标

指标定义清楚了,接下来就是定目标。SLA(Service Level Agreement)不是随便拍脑袋定的,它得跟业务场景挂钩。

1.2.1 如何设定合理的 SLA

我一般分三步走:

  1. 摸底:先跑一周的基准测试,拿到当前系统的真实数据。没有数据,一切免谈。
  2. 对标:看看竞品或者行业标准。比如,交易所的行情推送延迟通常在 10-50 微秒,你的系统如果比这个慢,那策略就没优势。
  3. 折中:在理想和现实之间找平衡。别一上来就定「P99 延迟 1 微秒」,那不叫目标,叫做梦。

一个典型的 SLA 示例:

  • 延迟:P50 < 5μs,P99 < 15μs,P99.9 < 50μs
  • 吞吐量:稳定支持 50,000 订单/秒,峰值 100,000 订单/秒
  • 抖动:P99 延迟与 P50 延迟的差值 < 10μs

1.2.2 别忘了「不可用时间」

很多人定 SLA 只盯着延迟和吞吐量,却忘了另一个关键指标:可用性

交易系统对可用性的要求极高。哪怕只宕机 1 秒,在极端行情下可能造成数百万的损失。我建议把可用性也纳入 SLA:

可用性等级 年宕机时间 适用场景
99.9% 8.76 小时 低频策略,可接受短暂中断
99.99% 52.56 分钟 中频策略,需要较高可靠性
99.999% 5.26 分钟 高频策略,几乎不允许宕机

1.3 基准测试:怎么量才准?

指标和 SLA 都定了,接下来就是测。但基准测试本身就有很多坑。

1.3.1 测试环境要「脏」

很多人喜欢在干净的开发环境上跑基准测试,结果数据漂亮得不行。一上生产环境,直接打回原形。

我建议:测试环境要尽量模拟生产环境的「脏」。比如:

  • 加上网络延迟模拟
  • 混入一些背景流量
  • CPU 和内存留一些余量,别跑满

小技巧: 我习惯在基准测试脚本里故意加一些「噪音线程」,模拟其他服务的资源争抢。这样测出来的数据才更接近真实情况。

1.3.2 工具选择

测延迟和吞吐量,工具很重要。我常用的几个:

  • wrk / wrk2:测 HTTP 接口的吞吐量和延迟分布,支持自定义线程和连接数。
  • JMH(Java Microbenchmark Harness):测 Java 代码片段的微基准,能帮你避开 JIT 预热和 GC 的坑。
  • perf / flamegraph:Linux 性能分析工具,配合火焰图看 CPU 到底花在哪了。

举个例子,用 JMH 测一个订单解码函数的延迟:

@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void decodeOrder() {
    Order order = OrderDecoder.decode(rawBytes);
}

跑完之后,JMH 会告诉你平均延迟、P50、P99 等百分位数据。嗯,这才是靠谱的基准。

1.4 小结:先定标准,再谈优化

这一章的内容其实就一句话:没有基准的优化都是耍流氓

你想想看,如果你连「延迟是多少」「抖动有多大」都不知道,你怎么知道优化有没有效果?你怎么跟老板交代?

所以,我的建议是:

  1. 先把延迟、吞吐量、抖动这三个指标定义清楚
  2. 根据业务场景设定合理的 SLA
  3. 用靠谱的工具跑基准测试,拿到真实数据

下一章,我们会聊到「如何从代码层面压榨性能」。但在此之前,请确保你已经把这一章的「尺子」造好了。否则,后面的优化你都不知道该往哪个方向使劲。

记住: 性能调优不是玄学,是科学。科学的第一步,就是测量。