欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

玩转MySQL基准测试:2.3章——深入理解测试步骤与方法

最编程 2024-02-29 11:35:16
...

在了解基本概念之后,现在可以来具体讨论一下如何设计和执行基准测试。但在讨论如何设计好的基准测试之前,先来看一下如何避免一些常见的错误,这些错误可能导致测试结果无用或者不精确:

  • 使用真实数据的子集而不是全集。例如应用需要处理几百 GB 的数据,但测试只有 1GB 数据,或者只使用当前数据进行测试,却希望模拟未来业务大幅度增长后的情况。
  • 使用错误的数据分布。例如使用均匀分布的数据测试,而系统的真实数据有很多热点区域(随机生成的测试数据通常无法模拟真实的数据分布)。
  • 使用不真实的分布参数。例如假定所有用户的个人信息都会被平均地读取。
  • 在多用户场景中,只做单用户的测试。
  • 在单服务器上测试分布式应用。
  • 与真实用户行为不匹配。
  • 反复执行同一查询。真实的查询是不尽相同的,这可能会导致缓存命中率降低,而反复执行同一查询在某种程度上会全部或者部分缓存结果。
  • 没有检查错误。如果测试的结果无法得到合理的解释,比如一个本应该很慢的查询突然变快了,就应该检查是否有错误产生,否则可能只是测试了 MySQL 检测语法错误的速度了。基准测试完成后,一定要检查一下错误日志,这应当是基本的要求。
  • 忽略了系统预热 ( warm up ) 的过程。例如系统重启后马上进行测试,有时候需要了解系统重启后需要多长时间才能达到正常的性能容量,要特别留意预热的时长。反过来说,如果想要分析正常的性能,需要注意的是,若基准测试在重启以后马上启动,则缓存是冷、还没有数据,这时即使测试的压力相同,得到的结果也和缓存已经装满数据时是不同的。
  • 使用默认的服务器配置。
  • 测试时间太短。基准测试需要持续一定的时间。

如果其他条件相同,就应努力使测试过程尽可能地接近真实应用的情况。当然,有时候和真实情况稍有些初入问题也不大。例如实际应用服务器和数据库服务器分别部署在不同的机器。如果采用和实际部署完全相同的配置当然更真实,但也会引入更多的变化因素,比如加入了网络的负载和速度等,而在单一节点上运行测试相对要容易,在某些情况下结果也可以接受,那么就可以在单一节点上进行测试。当然,这样的选择需要根据实际情况来分析是否合适。

2.3.1 设计和规划基准测试

规划基准测试的第一步是提出问题并明确目标,然后决定是采用标准的基准测试,还是设计专用的测试。

如果采用标准的基准测试,应该确认选择了合适的测试方案。例如,不要使用 TPC-H 测试电子商务系统。在 TPC 的定义中,“ TPC-H 是即席查询和决策支持型应用的基准测试”,因此不适合用来测试 OLTP  系统。

设计专用的基准测试是很复杂的,往往需要一个迭代的过程。「首先需要获得生产数据集的快照」,并且该快照很容易还原,以便进行后续的测试。「然后针对数据运行查询」。可以建立一个单元测试集作为初步的测试,并运行多遍,但是这和真是的数据库环境还是有差别的,更好的办法是选择一个有代表性的时间段,比如高峰期的一个小时或者一整天,记录生产系统上的所有查询。如果时间段选得比较小,则可以选择多个时间段。这样有助于覆盖整个系统的活动状态,例如每周报表的查询或者非峰值时间运行的批处理作业。

可以在不同级别记录查询。例如,如果是集成式 ( full-stack ) 基准测试,可以记录 Web 服务器上的 HTTP 请求,也可以打开 MySQL 的查询日志 ( Query Log )。倘若要重演这些查询,就要确保创建多线程并行执行,而不是单个线程线性地执行。对日志中的每个连接都应该创建独立的线程,而不是将所有的查询随机地分配到一些线程中。查询日志中记录了每个查询是在哪个连接中执行的。

即使不需要创建专用的基准测试,详细地写下测试规划也是必需的。测试可能要多次反复运行,因此需要精确地重现测试过程,而且也应该考虑到未来,执行下一轮测试时可能已经不是同一个人了。即使还是同一个人,也有可能不会确切地记得初次运行时的情况。测试规划应该记录测试数据、系统配置的步骤、如何测量和分析结果,以及预热的方案等。应该建立将参数和结果文档化的规范,每一轮测试都必须进行详细记录。文档规范可以很简单,比如采用电子表格或者记事本形式,也可以是复杂的自定义的数据库。需要记住的是,经常要写一写脚本来分析测试结果,因此如果能够不用打开电子表格或者文本文件等额外操作,当然是更好的。

2.3.2 基准测试应该运行多长时间

基准测试应该运行足够长的时间,如果需要测试系统在稳定状态时的性能,那么当然需要在稳定状态下测试并观察,而如果系统有大量的数据和内存,要达到稳定状态可能需要非常长的时间。大部分系统都会有一些应对突发情况的余量,能够吸收性能尖峰,将一些工作延迟到高峰期之后执行,但当对机器加压足够长时间之后,这些余量会被消耗尽,系统的短期尖峰也就无法维持原来的高性能。有时候无法确认测试需要运行多长的时间才足够,如果是这样,可以让测试一直运行,持续观察指导确认系统已经稳定。

2.3.3 获取系统性能和状态

在执行基准测试时,需要尽可能多地手机被测试系统的信息。最好为基准测试建立一个目录,并且每执行一轮测试都创建单独的子目录,将测试结果、配置文件、测试指标、脚本和其他相关说明都保存在其中。即使有些结果不是目前需要的,也应该先保存下来。多余一些数据总比缺乏重要的数据要好,而且多余的数据以后也许会用得着。需要记录的数据包括系统状态和性能指标,诸如 CPU 使用率、磁盘 I/O、网络流量统计、SHOW GLOBAL STATUS 计数器等。

2.3.4 获得准确的测试结果

获得准确测试结果的最好办法是回答一些关于基准测试的基本问题:是否选择了正确的基准测试?是否为问题收集了相关的数据?是否采用了错误的测试标准?

接着确认测试结果是否可重复。每次重新测试之前要确保系统的状态是一致的。如果是非常重要的测试,甚至有必要每次测试都重启系统。一般情况下,需要测试的是经过预热的系统,还需要确保预热的时间足够长、是否可重复。如果预热采用的是随机查询,那么测试结果可能就是不可重复的。

如果测试的过程会修改数据或者 schema,那么每次测试钱,需要利用快照还原数据。在表中插入 1000 条记录和 插入 100 万条记录,测试结果肯定不会相同。数据的碎片度和在磁盘上的分布,都可能导致测试是不可重复的。一个确保物理磁盘数据的分布尽可能一致的办法是,每次都进行快速格式化并进行磁盘分区复制。

很多因素,包括外部的压力、性能分析和监控系统、详细的日志记录、周期性作业以及其他一些因素,都会影响到测试结果。在每次测试中,修改的参数应该尽量少。如果必须要一次修改多个参数,那么可能会丢失一些信息。有些参数依赖其他参数,这些参数可能无法单独修改。有时候甚至都没意识到这些依赖,这给测试带来了复杂性。一般情况下都是通过迭代逐步地修改基准测试的参数,而不是每次运行时都做大量的修改。举个例子,如果要通过调整参数来创造一个特定行为,可以通过使用分治法 ( divide-and-conquer, 每次运行时将参数对分减半 ) 来找到正确的值。

另外,基于 MySQL 的默认配置的测试没有什么意义,因为默认配置是基于消耗很少内存的极小应用的。最后,如果测试中出现异常结果,不要轻易当做坏数据点而丢弃。应该认真研究并找到产生这种结果的原因。测试可能会得到有价值的结果,或者一个严重的错误,抑或基准测试的设计缺陷。

2.3.5 运行基准测试并分析结果

一旦准备就绪,就可以着手基准测试,收集和分析数据了。通常来说,自动化基准测试是个好主意。这样做可以获得更精确的测试结果,因为自动化的过程可以防止测试人员偶尔遗漏某些步骤,或者误操作。另外也有助于归档整个测试过程。

自动化的方式有很多,可以是一个 Makefile 文件或者一组脚本。脚本语言可以根据需要选择:shell、PHP、Perl 等都可以,要尽可能地使所有测试过程都自动化,包括装载数据、系统预热、执行测试、记录结果等。

一旦设置了正确的自动化操作,基准测试将成为一步式操作。如果只是针对某些应用做一次性的快速验证测试,可能就没必要做自动化。但只要未来可能会引用到测试结果,建议都尽量地自动化。否则到时候可能就搞不清楚是如何获得这个结果的,也不记得采用了什么参数,这样就很难再通过测试重现结果了。

基准测试通常需要运行多次。具体需要运行多少次要看对结果的记分方式,以及测试的重要程度。要提高测试的准确度,就需要多运行几次。一般在测试的实践中,可以取最好的结果值,或者所有结果的平均值,抑或从五个测试结果里取最好三个值的平均值。可以根据需要更进一步精确化测试结果,还可以对结果使用统计方法,确定置信区间等。不过通常来说,只要测试的结果能满足目前的需求,简单地运行几轮测试,看看结果的变化就可以了。如果结果变化很大,可以再多运行几次,或者运行更长的时间,这样都可以获得更准确的结果。

获得测试结果后,还需要对结果进行分析,也就是说,要把 “ 数字 ” 变成 “ 知识 ”。最终的目的是回答在设计测试时的问题。如何从数据中抽象出有意义的结果,依赖于如何收集数据。通常需要写一写脚本来分析数据,这不仅能减轻分析的工作量,而且和自动化基准测试一样可以重复运行,并易于文档化。