基准测试工具之你不知道的两三事 | 7.怎样做一场公平的性能对比

前面的文章中,我们已经能够构造纯写和读写混合负载,也知道单次结果不能轻易代表系统能力。接下来就到了基准测试最容易产生误解、也最有实际价值的一步:比较。

比较两个数据库版本、两种写入接口,甚至两款数据库时,真正的问题不是“谁的吞吐量更大”,而是“这两个结果是否真的在回答同一个问题”。如果工作负载、硬件、配置或运行过程不同,数字再漂亮也无法构成公平结论。

这一篇讨论怎样把一场性能对比设计成可复现、可解释的实验,而不是一张只有排名的表格。

1. 先确定:这轮到底要比较什么?

一次对比只能有一个清晰的研究对象。常见的对象包括:

想回答的问题对比对象应保持不变的内容
新版本是否带来写入退化同一数据库的两个版本硬件、数据规模、连接方式、写入负载与配置。
哪种写入接口更适合当前场景同一数据库的不同接口数据库版本、服务端配置、数据规模、客户端并发和负载。
两款数据库对同一场景的表现如何不同数据库产品硬件、逻辑数据、写入节奏、查询语义和运行次数。
批大小是否影响性能同一系统的两组参数BATCH_SIZE_PER_WRITE外的所有配置和环境。

“数据库 A 和数据库 B 谁更快”并不是一个足够完整的问题。至少还要说明:快的是哪一种负载,是纯写还是读写混合,写入是否允许乱序,查询是什么类型,以及用什么指标判断“更快”。

2. 建立一份对比实验方案

在运行之前,先把每轮测试要固定的东西写下来。它可以很短,但必须足够让后来的自己或其他人复现。

明确唯一对比对象

冻结环境与工作负载

分别执行多轮测试

检查失败数与日志

比较吞吐量和延迟范围

形成带边界的结论

这份“实验契约”至少应包含以下几部分:

类别需要记录的内容为什么不能省略
被测对象数据库名称、版本、写入接口、关键服务端设置这是唯一允许主动变化的部分。
机器环境CPU、内存、磁盘、网络、部署方式资源差异可能比软件差异更大。
数据负载设备数、测点数、数据类型、时间间隔、乱序比例它决定测试的数据形态。
操作负载写入/查询比例、查询范围、客户端数、批大小它决定系统实际面对的请求。
运行记录运行编号、完整配置、日志位置、开始时间它让异常结果可以被追溯。
结果口径写入与查询吞吐量、P99、成功与失败数它防止只挑选对自己有利的指标。

IoT Benchmark 的主配置、结果矩阵和延迟矩阵正好可以承载这份契约的大部分信息,但机器环境、服务端版本与部署方式仍需要额外记录。

3. 不要把“默认配置”当成公平配置

很多不公平比较并非出于主观选择,而是来自看似无害的默认差异。例如,两个数据库的连接方式不同、一个启用了压缩而另一个没有、一个测试使用本地 SSD 而另一个使用共享存储,或者一个系统测的是纯写,另一个测的是读写混合。

下面几种比较不能直接成立:

不可直接比较的情况为什么不成立正确做法
两组设备数、测点数或总点数不同处理的数据规模不同固定逻辑数据规模后再比较。
两组DB_SWITCH或接口不同请求路径和客户端开销不同要么固定接口,要么把“接口差异”明确设为唯一变量。
一组有乱序、一组无乱序写入顺序不同,存储代价也不同分别做顺序写和乱序写两组对比。
一组纯写、一组读写混合系统承受的负载类型不同为两组系统执行同一份操作比例。
一组出现失败、另一组全部成功成功处理的数据并不相同先解释失败并恢复可用性,再讨论性能。

这并不要求不同数据库的所有内部设置完全一致。内部实现本来就不同,不能强行把所有选项对齐。关键在于对外可见的工作负载和可用资源应相同,而每个系统自身的必要配置都应被记录。

4. 用基线和多轮结果替代“最好的一次”

任何一个被测对象都应该先获得自己的稳定基线,再进入比较。做法是:在同一环境、同一负载下连续运行多轮,记录写入与查询各自的吞吐量、P99 和失败数,观察它们通常落在哪个范围。

系统 A 多轮基线

得到 A 的稳定范围

系统 B 多轮基线

得到 B 的稳定范围

在相同口径下比较

差异是否稳定且无失败

核对日志与资源证据

继续验证,不下排名结论

记录结论与适用边界

单次最高吞吐量不应成为结论,因为它可能只是暂时的缓存状态或偶然波动。更可靠的表述是:在某个固定负载和环境下,系统 A 的多轮结果通常落在某个范围,系统 B 落在另一个范围;同时,两者的尾延迟和失败数分别如何。

若两个范围高度重叠,就不应强行给出“谁更快”的结论。此时可以诚实地说明:在当前负载和环境下,尚未观察到稳定差异;再根据业务需要扩大数据规模、调整负载或补充更多轮次。

5. 结果要按操作类型分别比较

当负载中既有写入又有查询时,不能用一个总吞吐量给系统排名。IoT Benchmark 会按操作类型给出成功数、失败数、吞吐量和延迟统计,比较时也应逐行阅读。

结果表现可以作出的判断还不能作出的判断
A 的写入吞吐更高、P99 更低,且两者均无失败当前纯写场景下 A 的写入表现更好A 在所有查询场景下都更好。
A 的写入更快,但 Q2 范围查询 P99 更高A 的写优化可能伴随该查询形态的代价A 整体体验一定更差。
A 与 B 吞吐接近,但 A 的失败数更高A 当前配置下的可用性或兼容性存在问题A 的性能更高。
一方只在某类聚合查询中落后差异与该查询路径有关所有读请求都会同样落后。

这张表背后的原则很简单:结论必须与负载和指标的粒度相同。测的是 Q2,就只对 Q2 下结论;测的是顺序写,就不能延伸到乱序写;测的是单机,就不能延伸到集群部署。

6. 写结论时,保留边界比写排名更重要

一份可信的对比结论通常包含四句话:

在什么环境、什么版本和什么负载下; 比较了哪些对象,唯一变化是什么; 多轮运行中观察到了哪些吞吐量、P99 和失败数范围; 这个结论不覆盖哪些场景。

例如,好的结论会说“在固定的顺序写入负载下,接口 A 的写入吞吐范围高于接口 B,且两者没有失败;本结果不代表乱序写入、范围查询或集群部署下的表现”。

这样的表述看似保守,实际更有价值:它让读者知道结论可以被复现,也知道什么时候不能套用。

7. 小结

公平的性能对比,不是把两组数字放在一起,而是让两组数字来自同一份问题、同一份负载和同一套可追溯条件。先明确唯一变量,冻结环境与 workload,再执行多轮测试,最后分别比较写入、查询、P99 和失败数。

在开始对比前,可以用下面的清单自查:

  1. 本轮比较的唯一对象是什么?
  2. 两组测试的机器环境与逻辑工作负载是否一致?
  3. 两组是否都成功完成,没有被失败数掩盖?
  4. 是否使用多轮范围,而非最好的一次?
  5. 结论是否明确了适用场景与不覆盖的边界?

当这些问题都有答案时,性能比较才不只是一次“跑分”,而能成为版本回归、接口选择和数据库选型的可靠依据。下一篇将继续讨论:怎样通过参数扫描找到并发与批大小的合理区间。

系列文章

  1. 第一篇:数据库基准测试工具是什么
  2. 第二篇:从一次时序数据库写入测试开始
  3. 第三篇:如何模拟线上写入负载
  4. 第四篇:如何读懂测试结果波动
  5. 第五篇:什么是读写混合负载
  6. 第六篇:如何模拟线上读写混合负载