什么是性能优化呢?其实我们往往从广义的定义是觉得一个MySQL系统的非功能性的优化都会看作是性能优化,比如我们会将数据库服务器的稳定性、每秒执行的SQL查询数目、系统的可扩展性、cpu利用率等等特性的优化都会看成是MySQL的性能优化。
我个人比较赞同本书的观点是MySQL性能优化应该就是指MySQL的查询响应时间的优化,MySQL性能优化就是将查询响应时间优化到一个客户或者用户体验能够接受的一个程度。
书中提到一个“基于目标的性能优化”的这个观点我是非常认同的,那么我们在这里讨论一下,为什么要基于目标进行优化呢?我们设想一下,当我们没有目标或者目标不明确的时候,比如我们的目标设定为将MySQL的性能优化到尽可能地快。这样的目标设定的时候,我们在执行具体的性能优化工作的时候就不知道该如何选择和排优先级了,影响性能的因素非常多,能够提升性能的工作也非常多,如果我们不加选择,每一项都去做,则将耗费非常高的成本,而这往往是不可行的,成本在一个商业组织里永远是有限的。如果我们选择不当的时候,很可能我们花费了大量的成本用在那些受益非常低的优化工作里,我相信这样的选择和做法绝对是不明智的,甚至是错误的。而性能优化这个领域也大致是遵循2/8原则的,也就是说80%的性能问题集中在20%的原因上,因此我们将成本花费在找到这20%的原因并解决这些性能问题将能获得80%的受益将会是一个非常明智的选择。
因此性能优化不是一场理想主义者对技术完美的追求,也不是一场不计成本的技术试验,它其实就是一场为达成目标而进行的商业活动,这个目标也一般是对外的,它可能是为了让用户响应时间达到500毫秒,也可能是让产品响应时间比其它竞品快50毫秒。它不是为了永无止境的追求完美,让系统的性能达到极致。因此我们在做性能优化的时候还要充分考虑到投入产出比,做出更加明智的选择。
性能优化流程应该是通用的,也同样适用于应用优化或者其它中间件的优化,而性能优化技术涉及到一些具体的工具和技术,通用性不强,但思路也是可以互相借鉴的。
另外具体的优化工具指针对Linux操作系统,因为互联网公司的MySQL生产绝大多数运行在Linux上,因此忽略其它OS平台。
我认为优化目标应该从用户出发,比如MySQL的用户是上游的调用方,即发出查询语句的应用程序,从上游获得优化目标,比如上游的期望是优化目标是达到响应时间的范围,如果上游无法确定的时候则应该继续再往上游找,则找到的可能就是前端应用,如果依然无法确定,则就是使用应用的用户对于性能的期望,根据产品要求以及竞品分析综合分析出性能需求。然后反向推导出对于MySQL的性能优化目标。最终得到MySQL的SQL语句的性能优化目标是类似于这样的:
在10月30日之前达到QPS1000的时候并且TP99小于10毫秒的目标。
设定的优化目标同样应该遵循SMART原则,即要求它是具体的(明确无歧义的,相关参与者都能够达成共识)、可衡量的(尽可能有数据来衡量目标)、可达到的(一般是在比较有把握的基础上增加20%的挑战)、其它目标相关的(对于产品和业务总体目标有促进作用)、有明确截至时间的。 按照这个原则去要求和修正自己的目标设定。
当然目标可能不是一蹴而就的,往往需要多次迭代才能获得更加准确合理的目标。
在影响MySQL性能的因素里可以首先分为宏观和微观的两大类,宏观的就是会影响几乎所有SQL的性能因素,比如一些共享的硬件资源(网络、CPU、内存、CPU等等)和软件资源(比如操作系统的资源限制配置、MySQL的执行线程、数据库锁)等等,这些宏观的因素对于MySQL的影响是全局的,它的影响范围比较广,因此这些性能问题因素的消除,它的收益相对微观因素是更高的;微观因素一般是指影响某一条或者少数几条SQL的性能因素,这些因素可能是SQL语句的执行复杂度太高或者在等待其它锁的释放等等。
本章节不详细介绍这些命令的具体用法,详细用法请参考相关的手册。
1.宏观系统测量
top Linux系统命令
查看系统启动信息、任务统计信息、cpu和内存等统计信息,还有进程的列表信息。这里我们可以重点关注mysqld进程的信息,对整个服务器系统有一个较为全面的了解。
iostat Linux系统命令
该命令可以监控Linux服务器上设备的io负载情况。通过查看负载,发现那些比较异常的磁盘io负载现象,通过一些异常数据的捕获能够发现问题的一些原因。比如mysql的磁盘io频繁,可能成为系统的性能瓶颈。
show global status MySQL命令。
该命令可以查看MySQL服务器的各种运行状态的汇总,可以重点关注与本次优化目标相关的状态数据进行分析。
show processlist MySQL命令。
该命令可以查看MySQL服务器执行线程的状态,重点关注哪些执行时间长的、阻塞状态的线程,分析这些线程上所运行的SQL语句。
查看MySQL慢查询日志
通过分析和查看慢查询日志,重点关注两类慢查询,执行比较耗时(比如大于100毫秒)执行非常频繁的;查询非常耗时(2000毫秒)的查询。这两类查询都是对于整个系统影响非常大的语句,重点分析和优化这样的SQL语句。具体选择哪些进行优化,还应该结合目标。
2.微观查询测量
explain
该命令时MySQL中用语分析select查询语句的执行计划的命令,通过该命令加上查询语句可以分析MySQL的执行计划,它使用哪个索引进行查询,有没有使用临时表,查询需要便利的记录数都会列举出来,一般通过该命令的分析都能查找出select语句性能差的原因,对于单条查询语句的优化这是一个非常好的工具。应该账号它。
show profile
该命令可以详细列举出执行某一个查询的每一个执行步骤的耗时分析,这对于深入优化某一个SQL语句非常有帮助,它时作为explian的一个重要的补充。
具体的分析方法本文不一一列举出,只讨论一下通用的原则和方法。
我们通过上一步的各种测量工具的数据捕获之后,就可以对这些各种状态和数据进行剖析,分析出性能的根本原因,那本文描述的一些通用的注意事项和原则是这样的。
1.测量的数据可能会有遗漏或者不准确。可能是工具的局限性或者工具本身的问题,会存在数据的不准确或遗漏,这个客观事实是要注意的。
2.剖析应该先用工具进行汇总,原则是先宏观再微观。
3.根据数据分析性能问题的原因。我们通过分析数据,找到一些异常的数据,对这些异常的数据的现象分析产生的原因。
4.针对根本原因设计优化方案。对症下药才能药到病除,一般不建议没有找到原则就根据猜测就设计几个方案去逐一尝试,这种尝试的方法成本是非常高的,当然也不是绝对的,在实在无法找到原因的时候也不失为一种最后的解决方案。
上一步得出的结论是性能问题的原因和对应的解决方案,这一步我们实施优化方案。实施方案一般应该选择在线下的模拟测试环境,或者线上的灰度测试环境上进行。不能够影响生产使用,而且原则是性能优化方案不能影响原来的功能的正确性,并且同时在实施的同时要考虑增加响应的监控点,这些监控点的目的就是收集数据,以验证优化方案的有效性。
把优化方案实施后的系统再进行一遍测量,记录下优化方案实施后的测试量数据。
将测量后的数据与优化前的进行对比,评估一下优化方案的有效性,是否达到了优化目标。
若已经达到了优化则可以停止进行优化了,切忌要抵制住完美主义的情节。
若未达成目标则要分析和沟通是否还要进一步进行优化,则可以继续执行3-5步循环迭代,直到结束为止。