多参说:多选参数优质学习资料分享,后台回复资料即可获取。
❝前言:第二章基准测试的内容有理论也有实践,这里村民并没有时间和精力为大家展现一些实践数据,仅摘录理论部分。如果大家对实践有兴趣,可以自行学习,肯定也是不错的经验。❞
基准测试 ( benchmark ) 是针对系统设计的一种压力测试,通常的目标是为了掌握系统的行为,但也有其他原因,如重现某个系统状态,或者是做新硬件的可靠性测试。本章将讨论 MySQL 和基于 MySQL 的应用的基准测试的重要性、策略和工具。
基准测试是唯一方便有效的、可以学习系统在给定的工作负载下会发生什么的方法。「基准测试可以观察系统在不同压力下的行为,评估系统的容量,掌握哪些是重要的变化,或者观察系统如何处理不同的数据」。基准测试可以在系统实际负载之外创造一些虚构场景进行测试。基准测试可以完成以下工作,或者更多:
基准测试还可以用于其他目的,比如为应用创建单元测试套件。
「基准测试的一个主要问题在于其不是真实压力的测试」。基准测试施加给系统的压力相对真实压力来说,通常比较简单。真实压力是不可预期而且变化多端的,有时候情况会过于复杂而难以解释,所以使用真实压力测试,可能难以从结果中分析出确切的结论。
基准测试的压力和真实压力有哪些方面不同?有很多因素会影响基准测试,比如数据量、数据和查询的分布,但「最重要的一点还是基准测试通常要求尽可能快地执行完成,所以经常给系统造成过大的压力」。在很多案例中,我们都会调整给测试工具的最大压力,以在系统可以容忍的压力阈值内尽可能快地执行测试,这对于系统的最大容量非常有帮助,然而大部分压力测试工具不支持对压力进行复杂的控制。务必记住,「测试工具自身的局限也会影响结果的有效性」。
在使用基准测试进行容量规划时也要掌握技巧,不能只根据测试结果做简单的推断。基本上,我们只能进行大概的测试来确定系统大致的余量有多少。当然也可以做一些真实压力测试(和基准测试有区别),但在构造数据集和压力的时候要特别小心,而且这样就不再是基准测试了。基准测试要尽量简单直接,结果之间容易相互比较,成本低且易于执行。尽管有很多限制,基准测试还是非常有用的。
「基准测试有两种主要的策略:一是针对整个系统的整体测试,另外是单独测试 MySQL。这两种策略也被称为集成式 ( full-stack ) 以及单组件式 ( single-component ) 基准测试」。针对整个系统做集成式测试,而不是单独测试 MySQL 的原因最主要有以下几点:
另外一方面,应用的整体基准测试很难建立,甚至很难正确设置。如果基准测试的设计有问题,那么结果就无法反映真实的情况,从而基于此做的决策也就可能是错误的。
不过有时候不需要了解整个应用的情况,而只需要关注 MySQL 的性能,至少在项目初期可以这样做。基于以下情况,可以选择只测试 MySQL:
另外,如果能够在真实的数据集上执行重复的查询,那么针对 MySQL 的基准测试也是有用的,但是数据本身和数据集的大小都应该是真实的。如果可能,可以采用生产环境的数据快照。
不幸的是,设置一个基于真实数据的基准测试复杂而且耗时。如果能得到一份生产数据集的拷贝,当然很幸运,但这通常不可能。比如要测试的是一个刚开发的新应用,它只有很少的用户和数据,如果像测试该应用在规模扩张到很大以后的性能表现,就只能通过模拟大量的数据压力来进行。
在开始执行甚至是在设计基准测试之前,需要先明确测试的目标。测试目标决定了选择什么样的测试工具和技术,以获得精确而有意义的测试结果。有时候需要用不同的方法测试不同的指标。比如,针对延迟 ( latency ) 和吞吐量 ( throughput ) 就需要采用不同的测试方法。请考虑以下指标,看看如何满足测试的需求。
归根结底,应该测试那些对用户来说最重要的指标。因此应该尽可能地去收集一些需求,比如什么样的响应时间是可以接受的、期待多少的并发性等等,然后基于这些需求来设计基准测试,避免目光短浅地只关注部分指标而忽略其他指标。
在了解基本概念之后,现在可以来具体讨论一下如何设计和执行基准测试。但在讨论如何设计好的基准测试之前,先来看一下如何避免一些常见的错误,这些错误可能导致测试结果无用或者不精确:
如果其他条件相同,就应努力使测试过程尽可能地接近真实应用的情况。当然,有时候和真实情况稍有些初入问题也不大。例如实际应用服务器和数据库服务器分别部署在不同的机器。如果采用和实际部署完全相同的配置当然更真实,但也会引入更多的变化因素,比如加入了网络的负载和速度等,而在单一节点上运行测试相对要容易,在某些情况下结果也可以接受,那么就可以在单一节点上进行测试。当然,这样的选择需要根据实际情况来分析是否合适。
规划基准测试的第一步是提出问题并明确目标,然后决定是采用标准的基准测试,还是设计专用的测试。
如果采用标准的基准测试,应该确认选择了合适的测试方案。例如,不要使用 TPC-H 测试电子商务系统。在 TPC 的定义中,“ TPC-H 是即席查询和决策支持型应用的基准测试”,因此不适合用来测试 OLTP 系统。
设计专用的基准测试是很复杂的,往往需要一个迭代的过程。「首先需要获得生产数据集的快照」,并且该快照很容易还原,以便进行后续的测试。「然后针对数据运行查询」。可以建立一个单元测试集作为初步的测试,并运行多遍,但是这和真是的数据库环境还是有差别的,更好的办法是选择一个有代表性的时间段,比如高峰期的一个小时或者一整天,记录生产系统上的所有查询。如果时间段选得比较小,则可以选择多个时间段。这样有助于覆盖整个系统的活动状态,例如每周报表的查询或者非峰值时间运行的批处理作业。
可以在不同级别记录查询。例如,如果是集成式 ( full-stack ) 基准测试,可以记录 Web 服务器上的 HTTP 请求,也可以打开 MySQL 的查询日志 ( Query Log )。倘若要重演这些查询,就要确保创建多线程并行执行,而不是单个线程线性地执行。对日志中的每个连接都应该创建独立的线程,而不是将所有的查询随机地分配到一些线程中。查询日志中记录了每个查询是在哪个连接中执行的。
即使不需要创建专用的基准测试,详细地写下测试规划也是必需的。测试可能要多次反复运行,因此需要精确地重现测试过程,而且也应该考虑到未来,执行下一轮测试时可能已经不是同一个人了。即使还是同一个人,也有可能不会确切地记得初次运行时的情况。测试规划应该记录测试数据、系统配置的步骤、如何测量和分析结果,以及预热的方案等。应该建立将参数和结果文档化的规范,每一轮测试都必须进行详细记录。文档规范可以很简单,比如采用电子表格或者记事本形式,也可以是复杂的自定义的数据库。需要记住的是,经常要写一写脚本来分析测试结果,因此如果能够不用打开电子表格或者文本文件等额外操作,当然是更好的。
基准测试应该运行足够长的时间,如果需要测试系统在稳定状态时的性能,那么当然需要在稳定状态下测试并观察,而如果系统有大量的数据和内存,要达到稳定状态可能需要非常长的时间。大部分系统都会有一些应对突发情况的余量,能够吸收性能尖峰,将一些工作延迟到高峰期之后执行,但当对机器加压足够长时间之后,这些余量会被消耗尽,系统的短期尖峰也就无法维持原来的高性能。有时候无法确认测试需要运行多长的时间才足够,如果是这样,可以让测试一直运行,持续观察指导确认系统已经稳定。
在执行基准测试时,需要尽可能多地手机被测试系统的信息。最好为基准测试建立一个目录,并且每执行一轮测试都创建单独的子目录,将测试结果、配置文件、测试指标、脚本和其他相关说明都保存在其中。即使有些结果不是目前需要的,也应该先保存下来。多余一些数据总比缺乏重要的数据要好,而且多余的数据以后也许会用得着。需要记录的数据包括系统状态和性能指标,诸如 CPU 使用率、磁盘 I/O、网络流量统计、SHOW GLOBAL STATUS 计数器等。
获得准确测试结果的最好办法是回答一些关于基准测试的基本问题:是否选择了正确的基准测试?是否为问题收集了相关的数据?是否采用了错误的测试标准?
接着确认测试结果是否可重复。每次重新测试之前要确保系统的状态是一致的。如果是非常重要的测试,甚至有必要每次测试都重启系统。一般情况下,需要测试的是经过预热的系统,还需要确保预热的时间足够长、是否可重复。如果预热采用的是随机查询,那么测试结果可能就是不可重复的。
如果测试的过程会修改数据或者 schema,那么每次测试钱,需要利用快照还原数据。在表中插入 1000 条记录和 插入 100 万条记录,测试结果肯定不会相同。数据的碎片度和在磁盘上的分布,都可能导致测试是不可重复的。一个确保物理磁盘数据的分布尽可能一致的办法是,每次都进行快速格式化并进行磁盘分区复制。
很多因素,包括外部的压力、性能分析和监控系统、详细的日志记录、周期性作业以及其他一些因素,都会影响到测试结果。在每次测试中,修改的参数应该尽量少。如果必须要一次修改多个参数,那么可能会丢失一些信息。有些参数依赖其他参数,这些参数可能无法单独修改。有时候甚至都没意识到这些依赖,这给测试带来了复杂性。一般情况下都是通过迭代逐步地修改基准测试的参数,而不是每次运行时都做大量的修改。举个例子,如果要通过调整参数来创造一个特定行为,可以通过使用分治法 ( divide-and-conquer, 每次运行时将参数对分减半 ) 来找到正确的值。
另外,基于 MySQL 的默认配置的测试没有什么意义,因为默认配置是基于消耗很少内存的极小应用的。最后,如果测试中出现异常结果,不要轻易当做坏数据点而丢弃。应该认真研究并找到产生这种结果的原因。测试可能会得到有价值的结果,或者一个严重的错误,抑或基准测试的设计缺陷。
一旦准备就绪,就可以着手基准测试,收集和分析数据了。通常来说,自动化基准测试是个好主意。这样做可以获得更精确的测试结果,因为自动化的过程可以防止测试人员偶尔遗漏某些步骤,或者误操作。另外也有助于归档整个测试过程。
自动化的方式有很多,可以是一个 Makefile 文件或者一组脚本。脚本语言可以根据需要选择:shell、PHP、Perl 等都可以,要尽可能地使所有测试过程都自动化,包括装载数据、系统预热、执行测试、记录结果等。
❝一旦设置了正确的自动化操作,基准测试将成为一步式操作。如果只是针对某些应用做一次性的快速验证测试,可能就没必要做自动化。但只要未来可能会引用到测试结果,建议都尽量地自动化。否则到时候可能就搞不清楚是如何获得这个结果的,也不记得采用了什么参数,这样就很难再通过测试重现结果了。 ❞
基准测试通常需要运行多次。具体需要运行多少次要看对结果的记分方式,以及测试的重要程度。要提高测试的准确度,就需要多运行几次。一般在测试的实践中,可以取最好的结果值,或者所有结果的平均值,抑或从五个测试结果里取最好三个值的平均值。可以根据需要更进一步精确化测试结果,还可以对结果使用统计方法,确定置信区间等。不过通常来说,只要测试的结果能满足目前的需求,简单地运行几轮测试,看看结果的变化就可以了。如果结果变化很大,可以再多运行几次,或者运行更长的时间,这样都可以获得更准确的结果。
获得测试结果后,还需要对结果进行分析,也就是说,要把 “ 数字 ” 变成 “ 知识 ”。最终的目的是回答在设计测试时的问题。如何从数据中抽象出有意义的结果,依赖于如何收集数据。通常需要写一写脚本来分析数据,这不仅能减轻分析的工作量,而且和自动化基准测试一样可以重复运行,并易于文档化。