4、基准测试设计:基准测试场景设计、交易负载模型、测试数据生成

基准测试这事儿,说白了就是给系统「照个CT」。你得知道它到底能扛多少压力,瓶颈在哪,极限在哪。我这些年做过的撮合引擎项目,但凡跳过这一步的,最后都回来补课了。嗯,咱们今天就把这块掰开揉碎讲清楚。

4.1 基准测试场景设计

场景设计不是拍脑袋。你得先想清楚:你要测什么?

我个人习惯把场景分成三类:

  • 吞吐量测试:系统每秒能处理多少笔订单?
  • 延迟测试:从订单进入系统到撮合完成,花了多少微秒?
  • 压力测试:在极限负载下,系统会不会崩?

举个例子。我之前做过一个期货撮合项目,客户说「我们日交易量100万笔」。我一听就知道,峰值肯定不止这个数。后来我们设计的基准场景是:峰值吞吐量按日均的5倍来压。结果呢?系统在3倍的时候就出现了锁竞争。幸亏提前测出来了。

核心原则:基准场景必须覆盖「正常负载」和「峰值负载」两个区间。峰值负载建议按正常值的3-5倍设计。

场景设计时还要考虑:

  • 订单类型比例:限价单、市价单、止损单各占多少?
  • 订单方向分布:买单和卖单的比例是否均衡?
  • 订单规模分布:小单多还是大单多?

我曾经踩过一个坑:测试时全是小单,系统跑得飞快。上线后大单一来,直接超时。为什么?因为大单的撮合逻辑更复杂,需要遍历更多的价格档位。所以场景设计一定要覆盖各种订单规模。

4.2 交易负载模型

负载模型,就是模拟真实交易行为。你不能随便扔一堆订单进去就完事。真实市场的订单流是有规律的。

4.2.1 订单流模型

订单流模型要模拟两个维度:到达率订单属性

到达率模型:

  • 泊松过程:适合模拟随机到达的订单流。我一般用这个做基准测试。
  • 自相似过程:适合模拟有突发性的市场行为。比如开盘、收盘时的订单洪峰。

订单属性模型:

  • 价格分布:围绕当前市场价格,按一定概率分布生成。
  • 数量分布:通常符合幂律分布——小单多,大单少。
  • 时间分布:订单的存活时间(即撤单前等待的时间)。

我的经验:别把订单到达率设成均匀的。真实市场是「一阵一阵」的。我习惯用「泊松过程 + 突发脉冲」的组合模型。先跑10秒平稳流,然后突然注入一波高峰,看看系统怎么反应。

4.2.2 市场数据模型

市场数据包括:行情快照、逐笔成交、深度变化。测试时你得模拟这些数据的生成和推送。

我个人建议:

  • 行情快照:每100ms生成一次。包含买卖各20档的挂单量。
  • 逐笔成交:每笔撮合完成后立即生成。
  • 深度变化:订单进入或撤出时触发。

这里有个容易忽略的点:市场数据的生成速度不能比订单处理速度慢。否则你测的就是数据生成器的性能,而不是撮合引擎的性能。我曾经犯过这个错,跑了一整天测试,结果发现瓶颈在行情推送线程上。尴尬。

4.3 测试数据生成

数据生成是基准测试的基础设施。你得有一套可靠的数据生成工具。

4.3.1 订单数据生成

我常用的生成策略:

// 伪代码示例:订单生成器核心逻辑
class OrderGenerator {
    // 价格围绕基准价随机波动
    price = basePrice + randomGaussian(0, spread);
    
    // 数量符合幂律分布
    quantity = pow(random(), -alpha) * maxQuantity;
    
    // 订单类型按比例分配
    type = weightedRandom([
        (LIMIT, 0.7),
        (MARKET, 0.2),
        (STOP, 0.1)
    ]);
    
    // 到达时间间隔符合泊松分布
    interval = -log(random()) / lambda;
}

生成的数据要满足几个条件:

  • 可重复性:用固定种子,保证每次测试数据一致。
  • 可调节性:能调整订单量、价格波动范围、订单类型比例。
  • 真实性:价格不能乱跳,要符合市场逻辑。

注意:千万别用随机数生成器直接生成价格。我见过有人生成的价格范围从1到100000,结果撮合引擎根本找不到匹配的对手单。正确的做法是:围绕一个基准价,用正态分布生成价格波动。

4.3.2 市场数据生成

市场数据生成要和订单流联动。你不能订单都撮合完了,行情还没更新。

我习惯的做法:

  • 预生成一批订单:先往订单簿里塞一些「背景订单」,模拟已有的挂单。
  • 实时注入新订单:按负载模型持续注入。
  • 同步生成行情:每次订单簿变化后,立即生成新的行情快照。

这里有个小技巧:预生成的背景订单数量,要占到总订单量的70%左右。为什么?因为真实市场中,大部分订单是挂在那等成交的,真正新进来的订单只占一小部分。这样测出来的结果才贴近真实。

4.4 测试数据规模与预热

数据规模怎么定?我有个简单的公式:

测试数据量 = 系统设计容量 × 测试时长(秒) × 1.5

多出来的0.5倍,是为了防止测试中途数据不够用。

另外,一定要做预热。JVM也好,内存池也好,刚启动时性能都不稳定。我一般先跑3分钟「热身」,让系统进入稳定状态,再开始记录数据。

预热建议:用测试数据量的20%做预热。预热完成后,重置统计指标,再开始正式测试。

4.5 知识体系总览

下面这张图,是我对基准测试设计的整体理解。你可以把它当作一个检查清单:

基准测试设计知识体系 场景设计 • 吞吐量测试 • 延迟测试 • 压力测试 • 峰值负载(3-5倍) • 订单类型比例 负载模型 • 订单流模型 - 泊松过程 - 自相似过程 • 市场数据模型 • 价格/数量分布 数据生成 • 订单数据生成 • 市场数据生成 • 可重复性 • 可调节性 • 真实性 关键注意事项 1. 预热3分钟,用20%数据量热身 2. 数据量 = 设计容量 × 测试时长 × 1.5 3. 背景订单占70%,新订单占30% 4. 价格用正态分布,围绕基准价波动 测试流程:场景定义 → 负载建模 → 数据生成 → 预热 → 正式测试 → 结果分析

基准测试设计,说白了就是「模拟真实、覆盖极端、保证可重复」。你把这三点做到位了,测试结果就有说服力。我见过太多团队,测试数据随便生成,场景随便设计,最后测出来的数据根本不敢拿给老板看。嗯,咱们别犯这种错。

最后一个小建议:每次测试完,把测试场景、数据种子、结果都存档。这样下次优化后,可以跑同样的测试做对比。我习惯用「场景名_日期_版本号」的命名方式,方便回溯。

专注资料整理