(1)概述:
有时候我们在执行查询或者更新语句的时候,可能SQL语句的性能会出现不正常的莫名抖动,平时可能几十毫秒搞定,现在居然要几秒钟,其实这种抖动,通过分析底层原理,根本原因有两个:
第一个 可能buffer pool的缓存页都满了,此时执行一个SQL查询很多数据,瞬间把很多缓存页flush到磁盘上去,刷磁盘太慢,就导致查询语句执行的很慢。因为必须等很多缓存页都flush到磁盘,才能执行查询从磁盘把需要的数据页加载到buffer pool的缓存页里。
第二个 可能执行更新语句的时候,redo log在磁盘文件的所有文件都写满了,此时需要回到第一个redo log文件覆盖写,覆盖写的时候可能就涉及到第一个redo log文件里有很多redo log 日志对应的更新操作改动了缓存页,那些缓存页还没flush到磁盘,此时就必须把那些缓存页flush到磁盘,才能执行后续的更新语句,这一过程必然导致更新执行的慢了。
(2)如何解决上面的问题:
第一是 尽量减少缓存页flush到磁盘的频率,
第二是 尽量提升缓存页flush到磁盘的速度,
尽量减少缓存页flush到磁盘的频率这个是很难控制的,因为平时缓存页就是正常的使用,迟早会被填满。我们主要是针对第二个核心点的优化,就是如何尽量提升缓存页flush到磁盘的速度。
举例:
执行一个SQL查询语句,此时需要等待flush一批缓存页到磁盘,接着才能加载查询出来的数据到缓存页。如果flush到磁盘的是1s,SQL查询200ms,这条SQL执行完毕的时间是1.2s。但是如果缓存页flush到磁盘的时间优化到100ms,然后加上SQL查询200ms,那就是300ms,性能提升很多。
所以关键是尽可能减少flush缓存页到磁盘的时间开销到最小,如何做到这点就是尽量使用SSD固态硬盘,而不是机械硬盘,因为SSD固态硬盘最强大的地方就是它的随机IO性能很高。而flush到磁盘就是典型的随机IO,其次只用SSD固态硬盘还不够,需要设置数据库的一个参数,**innodb_io_capacity**,这个参数告诉数据库采用多大的IO速率把缓存页flush到磁盘里去。但是需要把SSD 固态硬盘的随机IO性能发挥出来。<br /> 所以建议对数据库部署机器的SSD固态硬盘能承载的最大随机IO速率做一个测试,可以使用 **fio 工具**来测试。查询SSD最大随机IO速率后,就可以知道每秒执行多少次随机IO了,此时把这个值设置给数据库的 inndodb_io_capacity ,尽可能的让数据库用最大速率flush缓存页到磁盘。<br /> 另外,实际flush的时候,其实会按照 innodb_io_capacity * 百分比 来进行刷盘,这个比例就是脏页的比例,是 **innodb_max_dirty_pages_pct**参数控制,默认是75%,这个一般不动,我们核心关注的就是把 innodb_io_capacity 调整为SSD的最大随机IO速率就可以了。
还有一个参数,innodb_flush_neighbors 意思是说,在flush缓存页到磁盘的时候,控制缓存页临近的其他缓存页到磁盘,但是这样会导致flush缓存页太多,如果使用SSD固态硬盘就没这个必要了,可以把 innodb_flush_neighbors参数设置为0,禁止刷临近缓存页,这样每次刷新的缓存页数量降低到最少。
所以针对这个案例,就是MySQL随机抖动的问题,最核心的就是把 innodb_io_capacity 设置为 SSD 固态硬盘的 IOPS,让他刷缓存页尽量快,同时设置innodb_flush_neighbors为0,不让每次刷临近缓存页。