注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭研后台技术中心的博客

 
 
 
 
 

日志

 
 

针对SSD的MySQL IO优化  

来自郭忆   2013-11-28 23:12:55|  分类: 默认分类 |举报 |字号 订阅

  下载LOFTER 我的照片书  |

网易私有云关系数据库服务RDS最近发布了新的版本,其中最为吸引人的一个特性无疑是允许用户在创建实例和从一个备份文件恢复实例的时候可以指定SSD作为硬盘介质,我们前期对SSD进行了充分的测试,这其中当然包括最为关键的性能测试部分。下面就跟大家分享一下在SSD性能测试过程中遇到的一个问题和解决问题的思路。

我们的性能测试使用的测试工具是Sysbench,测试场景主要包括5类:全内存非事务更新(nontrx)、全内存事务更新(complex)、非全内存查询(select)、非全内存非事务更新(nontrx)、非全内存的事务更新(complex)。在非全内存的事务更新测试中,我们发现了一个奇怪的现象,如下图所示:

针对SSD的MySQL IO优化 - 网易杭研后台技术中心 - 网易杭研后台技术中心的博客

MySQL实例的TPS会出现周期性的降到0的现象,要解释这个想象,我们首先就要先分析一下MySQL事务提交的流程。

MySQL一般使用Innodb作为底层存储引擎,而Innodb是一种基于磁盘存储的系统,即所有的数据最终都需要保存在磁盘上。为了提高效率,MySQL使用了内存缓冲池的技术,对于每次用户的更新请求,如果用户需要更新的数据已经在缓冲池中,则直接更新内存的缓冲池;如果缓冲池未命中,Innodb会将要更新的数据页先从磁盘读入内存,然后进行更新,也就是说所有的更新都是在内存中完成的

内存中被更新的数据页我们称之为脏页,脏页最终再通过异步的方式刷新到磁盘上。为了保证事务的ACID特性,所有对缓冲池中的数据的更新都需要记日志,称为重做日志(redo log)或者Innodb存储引擎日志。一旦MySQL崩溃,系统就可以根据redo log将原先未刷新到磁盘上的更新刷新到磁盘上,这样就保证了数据不会丢失。

但是内存能够容纳的脏页是有限的,同时由于redo log只有记录的更新刷新到磁盘,redo log才可以被覆盖重写,所以MySQL使用了检查点的技术,根据一定的策略将内存中的脏页刷出到磁盘上。

针对SSD的MySQL IO优化 - 网易杭研后台技术中心 - 网易杭研后台技术中心的博客

如图所示,经过上面4个步骤,用户的更新才会真正落到磁盘上。所谓检查点,本质上就是redo log的一个偏移量,该位置之前的日志所记录的更新一定已经刷新到磁盘上了,所以该位置之前的日志都是可以被覆盖重写的,这也意味着在MySQL崩溃恢复时,检查点之前的更新由于一定是已经刷新到磁盘上了,所以是不需要重做的,可以直接跳过。

所以整个日志空间可以描述为下面这个图。
针对SSD的MySQL IO优化 - 网易杭研后台技术中心 - 网易杭研后台技术中心的博客

为了保证未刷脏页的redo log不被覆盖,MySQL使用了下面的脏页刷新策略,例如当log cap 大于整个日志空间的75%时,系统会异步的将log cap部分的日志涉及的脏页刷到磁盘上,但是此时事务提交不会终止,也就是说还允许有redo log的继续写入。但是如果log cap继续增加,当超过整个日志空间的90%时,MySQL会停止事务的更新,此时redo log也会停止写入,必须等到刷足够的脏页时,才能允许事务再次提交。本质上说,
如果事务提交的速度大于脏页刷盘的速度,最终都会触发上述日志保护的功能,即最终系统停止事务的更新,来保证日志记录的脏页能够刷新到磁盘上

这就解释了我们上面看到的TPS出现周期性的降到0的情况,但是有一个疑问,为什么在物理盘上却很少看到上述的情况呢?这要从SSD IO特性讲起。普通的机械磁盘是依靠磁头移动来实现数据的定位的,所以其随机读写能力受限于磁盘的转速,相对于SSD有非常明显的差距,而顺序IO,普通机械磁盘相对于SSD,并没有太多的差距。那就有个疑问,日志本身是顺序IO,在SSD上和物理磁盘上写日志本身应该没有太大的差别,但是千万不要忘记,在写日志的时候,同时也在刷脏页,为了保证事务安全,一般我们会设置每次事务提交都会刷新log buffer到磁盘,而log buffer默认8M,本身是很小的IO,刷脏页是随机IO,刷脏页和写日志交错进行,磁盘的IO也不再顺序IO,而会变成随机IO,这样物理磁盘和SSD就会出现差别,SSD虽然会有写放大的因素,随机写相对随机读性能较差,但是相对于普通机械磁盘,还是有非常大的优势的,所以SSD就会出现日志的写入速度远远大于检查点的推进速度,但是在普通物理机械磁盘上,就不容易出现,因为刷脏页的随机IO会拖慢事务的提交速度,日志写入序号与检查点之间的差距增长不会那么快。这也就是为什么在SSD的场景下更容易出现MySQL TPS周期性波动的原因。

分析清楚了问题产生的原因,下一步我们来看看有什么办法来解决这个问题。首先,问题产生的原因归根到底就是脏页刷的太慢,事务提交的太快,日志空间不足以支撑他们之间速度的差距。事务提交的速度我们固然无法让其降低,但是我们可以从加快脏页的刷新来想想办法。Innodb在刷脏页的时候有一个关键特性就是会将脏页临近的脏页一并刷出,这样也可以将随机IO转化成顺序IO,当然,如果脏页被再次更新,就会存在重复刷新的问题,但是对于普通磁盘而言,这点开销是完全值得的。但是对于SSD,随机IO能力相对于顺序IO并没有非常大的差距,所以完全可以关闭刷新邻接脏页!这样一方面可以减少脏页刷新的数量,另一方面也可以避免脏页再次被更新后出现的重复刷新的问题。

在MySQL中一次刷新的脏页的数量有一个 innodb_io_capacity的参数进行控制, innodb_io_capacity越大,一次刷新的脏页的数量也就越大,在SSD的场景下,由于IO能力大大增强,所以 innodb_io_capacity需要调高,可以配置到2000以上,但是对于普通机械磁盘,由于其随机IO的IOPS最多也就是300,所以 innodb_io_capacity开的过大,反而会造成磁盘IO不均匀。最后还需要再提一点,就是可以在SSD的场景下适当增大redo log的大小,当然这个不能从根本解决上述TPS 波动的问题,只是能够将两次TPS波动的距离拉长。经过上述优化测试,我们得到对于结果如下图所示:

针对SSD的MySQL IO优化 - 网易杭研后台技术中心 - 网易杭研后台技术中心的博客
 
红色是优化后的TPS曲线,蓝色是原先的TPS曲线,TPS周期性的降到0的问题消失啦!


——EOF——

 


  评论这张
 
阅读(8356)| 评论(2)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017