前面的文章中我们已经能够构造纯写和读写混合负载也知道单次结果不能轻易代表系统能力。接下来就到了基准测试最容易产生误解、也最有实际价值的一步比较。比较两个数据库版本、两种写入接口甚至两款数据库时真正的问题不是“谁的吞吐量更大”而是“这两个结果是否真的在回答同一个问题”。如果工作负载、硬件、配置或运行过程不同数字再漂亮也无法构成公平结论。这一篇讨论怎样把一场性能对比设计成可复现、可解释的实验而不是一张只有排名的表格。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 和失败数。在开始对比前可以用下面的清单自查本轮比较的唯一对象是什么两组测试的机器环境与逻辑工作负载是否一致两组是否都成功完成没有被失败数掩盖是否使用多轮范围而非最好的一次结论是否明确了适用场景与不覆盖的边界当这些问题都有答案时性能比较才不只是一次“跑分”而能成为版本回归、接口选择和数据库选型的可靠依据。下一篇将继续讨论怎样通过参数扫描找到并发与批大小的合理区间。系列文章第一篇数据库基准测试工具是什么第二篇从一次时序数据库写入测试开始第三篇如何模拟线上写入负载第四篇如何读懂测试结果波动第五篇什么是读写混合负载第六篇如何模拟线上读写混合负载