基准测试(benchmark)是MySQL新手和专家都需要掌握的一项基本技能。简单地说, 基准测试是针对系统设计的一种压力测试。通常的目标是为了掌握系统的行为。但也有其他原因, 如重现某个系统状态, 或者是做新硬件的可靠性测试。本章将讨论MySQL和基千MySQL的应用的基准测试的重要性策略和工具。我们将特别讨论一下sysbench, 这是一款非常优秀的MySQL基准测试工具。
2.1为什么需要基准测试
基准测试是唯一方便有效的、可以学习系统在给定的工作负载下会发生什么的方法。基准测试可以观察系统在不同压力下的行为, 评估系统的容量, 掌握哪些是重要的变化, 或者观察系统如何处理不同的数据。基准测试可以在系统实际负载之外创造一些虚构场景进行测试。基准测试可以完成以下工作, 或者更多:
• 验证基于系统的一些假设, 确认这些假设是否符合实际情况。
• 重现系统中的某些异常行为, 以解决这些异常。
• 测试系统当前的运行情况。如果不清楚系统当前的性能, 就无法确认某些优化的效
果如何。也可以利用历史的基准测试结果来分析诊断一些无法预测的问题。
• 模拟比当前系统更高的负载, 以找出系统随着压力增加而可能遇到的扩展性瓶颈。
• 规划未来的业务增长。基准测试可以评估在项目未来的负载下, 需要什么样的硬件,需要多大容量的网络, 以及其他相关资源。这有助于降低系统升级和重大变更的风险。
• 测试应用适应可变环境的能力。例如, 通过基准测试, 可以发现系统在随机的并发峰值下的性能表现, 或者是不同配置的服务器之间的性能表现。基准测试也可以测试系统对不同数据分布的处理能力。
• 测试不同的硬件、软件和操作系统配置。比如RAID 5还是RAID 10更适合当前的系统?如果系统从ATA硬盘升级到SAN存储,对千随机写性能有什么帮助? Linux2.4系列的内核会比2.6系列的可扩展性更好吗?升级MySQL的版本能改善性能吗?为当前的数据采用不同的存储引擎会有什么效果?所有这类问题都可以通过专门的基准测试来获得答案。
• 证明新采购的设备是否配置正确。笔者曾经无数次地通过基准测试来对新系统进行压测,发现了很多错误的配置,以及硬件组件的失效等问题。因此在新系统正式上线到生产环境之前进行基准测试是一个好习惯,永远不要相信主机提供商或者硬件供应商的所谓系统已经安装好,井且能运行多快的说法。如果可能,执行实际的基准测试永远是一个好主意。
基准测试还可以用于其他目的,比如为应用创建单元测试套件。但本章我们只关注与性能有关的基准测试。
基准测试的一个主要问题在于其不是真实压力的测试。基准测试施加给系统的压力相对真实压力来说,通常比较简单。真实压力是不可预期而且变化多端的,有时候情况会过于复杂而难以解释。所以使用真实压力测试,可能难以从结果中分析出确切的结论。
结论就是,我们只能进行大概的测试,来确定系统大致的余量有多少。当然也可以做一些真实压力测试(和基准测试有区别),但在构造数据集和压力的时候要特别小心,而且这样就不再是基准测试了。基准测试要尽量简单直接,结果之间容易相互比较,成本低且易于执行。尽管有诸多限制,基准测试还是非常有用的(只要搞清楚测试的原理,并且了解如何分析结果所代表的意义)。
2.2基准测试的策略
基准测试有两种主要的策略: 一是针对整个系统的整体测试,另外是单独测试MySQL。这两种策略也被称为集成式(full-stack)以及单组件式(single-component)基准测试。针对整个系统做集成式测试,而不是单独测试MySQL的原因主要有以下几点:
• 测试整个应用系统,包括Web服务器、应用代码、网络和数据库是非常有用的,因为用户关注的井不仅仅是MySQL本身的性能,而是应用整体的性能。
• MySQL并非总是应用的瓶颈,通过整体的测试可以揭示这一点。
• 只有对应用做整体测试,才能发现各部分之间的缓存带来的影响。
• 整体应用的集成式测试更能揭示应用的真实表现,而单独组件的测试很难做到这一点。
另外一方面,应用的整体基准测试很难建立,甚至很难正确设置。如果基准测试的设计有问题,那么结果就无法反映真实的情况,从而基千此做的决策也就可能是错误的。
不过,有时候不需要了解整个应用的情况,而只需要关注MySQL的性能,至少在项目初期可以这样做。基于以下情况,可以选择只测试MySQL:
• 需要比较不同的schema或查询的性能。
• 针对应用中某个具体问题的测试。
• 为了避免漫长的基准测试,可以通过一个短期的基准测试,做快速的“ 周期循环",来检测出某些调整后的效果。
另外,如果能够在真实的数据集上执行重复的查询,那么针对MySQL的基准测试也是有用的,但是数据本身和数据集的大小都应该是真实的。如果可能,可以采用生产环境的数据快照。
2.2.1测试何种指标
在开始执行甚至是在设计基准测试之前,需要先明确测试的目标。测试目标决定了选择什么样的测试工具和技术,以获得精确而有意义的测试结果。可以将测试目标细化为一系列的问题,比如,“这种CPU是否比另外一种要快?", 或“新索引是否比当前索引性能更好?”
请考虑以下指标,看看如何满足测试的需求。
吞吐量
吞吐量指的是单位时间内的事务处理数。这一直是经典的数据库应用测试指标。一些标准的基准测试被广泛地引用, 如TPC-C, 而且很多数据库厂商都努力争取在这些测试中取得好成绩。这类基准测试主要针对在线事务处理(OLTP) 的吞吐量, 非常适用于多用户的交互式应用。常用的测试单位是每秒事务数(TPS), 有些也采用每分钟事务数(TPM)。
响应时间或者延迟
这个指标用于测试任务所需的整体时间。根据具体的应用,测试的时间单位可能是微秒、毫秒、秒或者分钟。根据不同的时间单位可以计算出平均响应时间、最小响应时间、最大响应时间和所占百分比。最大响应时间通常意义不大, 因为测试时间越长, 最大响应时间也可能越大。而且其结果通常不可重复, 每次测试都可能得到不同的最大响应时间。因此, 通常可以使用百分比响应时间(percentile responsetime)来替代最大响应时间。例如, 如果95%的响应时间都是5毫秒, 则表示任务在95%的时间段内都可以在5毫秒之内完成。使用图表有助于理解测试结果。可以将测试结果绘制成折线图(比如平均值折线或者95%百分比折线)或者散点图, 直观地表现数据结果集的分布情况。通过这些图可以发现长时间测试的趋势。本章后面将更详细地讨论这一点。
并发性
并发性是一个非常重要又经常被误解和误用的指标。例如, 它经常被表示成多少用户在同一时间浏览一个Web站点,经常使用的指标是有多少个会话。然而,HTTP协议是无状态的, 大多数用户只是简单地读取浏览器上显示的信息, 这井不等同于Web服务器的井发性。而且,Web服务器的井发性也不等同于数据库的并发性, 而仅仅只表示会话存储机制可以处理多少数据的能力。Web服务器的井发性更准确的度量指标, 应该是在任意时间有多少同时发生的并发请求。
在应用的不同环节都可以测量相应的井发性。Web服务器的高并发, 一般也会导致数据库的高井发,但服务器采用的语言和工具集对此都会有影响。注意不要将创建数据库连接和并发性搞混淆。一个设计良好的应用, 同时可以打开成百上千个MySQL数据库服务器连接,但可能同时只有少数连接在执行查询。所以说,一个Web站点“ 同时有50 000 个用户” 访问, 却可能只有10 - 15个并发请求到MySQL数据库。
换句话说,并发性基准测试需要关注的是正在工作中的并发操作,或者是同时工作中的线程数或者连接数。当并发性增加时,需要测量吞吐量是否下降,响应时间是否变长,如果是这样,应用可能就无法处理峰值压力。
井发性的测量完全不同于响应时间和吞吐量。它不像是一个结果,而更像是设置基准测试的一种属性。井发性测试通常不是为了测试应用能达到的井发度,而是为了测试应用在不同并发下的性能。当然,数据库的并发性还是需要测量的。可以通过sysbench指定32 、64或者128个线程的测试,然后在测试期间记录MySQL数据库的Threads_ running状态值。在第11章将讨论这个指标对容最规划的影响。
可扩展性
在系统的业务压力可能发生变化的情况下,测试可扩展性就非常必要了。第11章将更进一步讨论可扩展性的话题。简单地说,可扩展性指的是,给系统增加一倍的工作,在理想情况下就能获得两倍的结果(即吞吐量增加一倍)。或者说,给系统增加一倍的资源(比如两倍的CPU数),就可以获得两倍的吞吐量。当然,同时性能(响应时间)也必须在可以接受的范围内。大多数系统是无法做到如此理想的线性扩展的。随着压力的变化,吞吐址和性能都可能越来越差。
可扩展性指标对于容量规范非常有用, 它可以提供其他测试无法提供的信息,来帮助发现应用的瓶颈。比如,如果系统是基于单个用户的响应时间测试(这是一个很糟糕的测试策略) 设计的, 虽然测试的结果很好,但当井发度增加时,系统的性能有可能变得非常糟糕。而一个基千不断增加用户连接的情况下的响应时间测试则可以发现这个问题。
一些任务,比如从细粒度数据创建汇总表的批量工作,需要的是周期性的快速响应时间。当然也可以测试这些任务纯粹的响应时间,但要注意考虑这些任务之间的相互影响。批批工作可能导致相互之间有影响的查询性能变差,反之亦然。
归根结底,应该测试那些对用户来说最重要的指标。因此应该尽可能地去收集一些需求,比如,什么样的响应时间是可以接受的,期待多少的井发性,等等。然后基于这些需求来设计基准测试,避免目光短浅地只关注部分指标,而忽略其他指标。
2.3基准测试方法
避免一些常见的错误,这些错误可能导致测试结果无用或者不精确:
• 使用真实数据的子集而不是全集。例如应用需要处理几百GB的数据,但测试只有1GB数据,或者只使用当前数据进行测试,却希望模拟未来业务大幅度增长后的情况。
• 使用错误的数据分布。例如使用均匀分布的数据测试,而系统的真实数据有很多热点区域(随机生成的测试数据通常无法模拟真实的数据分布)。
• 使用不真实的分布参数,例如假定所有用户的个人信息(profile)都会被平均地读取
• 在多用户场景中,只做单用户的测试。
• 在单服务器上测试分布式应用。
• 与真实用户行为不匹配。例如Web页面中的“思考时间”。真实用户在请求到一个页面后会阅读一段时间,而不是不停顿地一个接一个点击相关链接。反复执行同一个查询。真实的查询是不尽相同的,这可能会导致缓存命中率降低。而反复执行同一个查询在某种程度上,会全部或者部分缓存结果。
• 没有检查错误。如果测试的结果无法得到合理的解释,比如一个本应该很慢的查询突然变快了,就应该检查是否有错误产生。否则可能只是测试了MySQL检测语法错误的速度了。基准测试完成后,一定要检查一下错误日志,这应当是基本的要求。
• 忽略了系统预热(warm up)的过程。例如系统重启后马上进行测试。有时候需要了解系统重启后需要多长时间才能达到正常的性能容量,要特别留意预热的时长。反过来说,如果要想分析正常的性能,需要注意,若基准测试在重启以后马上启动,则缓存是冷的、还没有数据,这时即使测试的压力相同,得到的结果也和缓存已经装满数据时是不同的。
• 使用默认的服务器配置。第3章将详细地讨论服务器的优化配置。
• 测试时间太短。基准测试需要持续一定的时间。后面会继续讨论这个话题。
只有避免了上述错误,才能走上改进测试质量的漫漫长路。
如果其他条件相同,就应努力使测试过程尽可能地接近真实应用的情况。当然,有时候和真实情况稍有些出入问题也不大。例如,实际应用服务器和数据库服务器分别部署在不同的机器。如果采用和实际部署完全相同的配置当然更真实,但也会引入更多的变化因素,比如加入了网络的负载和速度等。而在单一节点上运行测试相对要容易,在某些情况下结果也可以接受,那么就可以在单一节点上进行测试。当然,这样的选择需要根据实际情况来分析是否合适。