之前没经历过漫长的crash recovery恢复过程,一是本身库中的数据量就不大,平时的业务量就不是很高,二是innodb_buffer_pool_size和innodb_log_file_size的大小平时设置的也不大。所以,对于意外导致innodb自动恢复时,经历的等待时间的长短没有什么深刻的体会。在浏览peter很早以前的文章时,看到当时大家是多么的无奈和痛苦,同时,在InnoDB没有对其作出改进之前,大家都在开动脑筋,配合各种参数尽可能的缩短故障恢复的时间。先来了解下,什么是Crash Recovery,它究竟都帮我们做了什么。
Innodb Crash Recovery
这也是InnoDB引擎的一个特点,当故障发生,重新启服务后,会自动完成恢复操作,将数据库恢复到之前一个正常状态。恢复进程会完成两步,第一步:检查redo日志,将之前完成并提交的事务全部重做;第二步:将undo日志中,未完成提交的事务,全部取消。那么,就仅仅做了这么两步为什么恢复过程会变得如此漫长呢?在InnoDB未对恢复速度做提升之前,MySQL的bug列表中,曾被提出了两个改进请求:Bug #29847和Bug #49535。
“民间办法”— 治标不治本
方法1:重启mysqld之前,暂时减小innodb_buffer_pool_size的大小,将innodb_flush_method=O_DIRECT临时注释掉,会缩短故障恢复的时间。
方法2:一开始就把my.cnf中参数innodb_log_file_size的大小设置的小些,该选项与恢复时间的长短有直接关系,但太小也会对性能造成影响。
“专业解决” — 改进代码
Bug #49535提到,在恢复期间重做redo日志时,检查可用内存的大小将消耗超过90%的CPU。恢复redo日志时,会在buffer pool中开辟一块空间,用来的将redo log从磁盘中读到内存当中,放到一个hash table里面,随着读出redo log的增加,这个hash table会不断增大,为了保证该空间不超过buffer pool的大小,所以,每读入一次redo log都要去遍历一遍hash table来获得其大小,显然效率低下而且很耗资源。解决办法是在hash table的结构中加入一个头字段来单独记录总的大小。
Bug #29847是由flush list过大导致。当每执行一条日志后,都会被插入到一个叫作flush list的列表中,也就是我们说的dirty page列表,正常情况下有跟新完成,那么新的跟新会被放到列表的前面,而当发生恢复时,每次跟新的记录都会按照之前LRU的顺序放到原来的位置,同时,不幸的是这个flush list又是一个古老的链表结构,每次插入的遍历痛苦,你懂得!flush list变的越长将消耗的时间就越久,所以,为什么之前提到,减小innodb_log_file_size的大小,能有效的缩短恢复时间,其实,是为了减少flush list的大小。解决办法是采用一种叫做红黑树(red-black tree)的数据结构,这个我还没有看明白:) 在pluin 1.0.7以后就没有恢复太久的问题了,为了提高性能完全可以尽可能的加大redo log的设置,InnoDB也保证了不会再有超长恢复等待的发生。
p.s.:除了peter,又发现一个很猛的人domas,有思想有深度。【此外,有种幻觉就是,MySQL圈里似乎日本技术要比中国技术强好多,Yasufumi Kinoshita、Yoshinori.Matsunobu、TokuDB(updated on 11/05/: 惭愧呀,一直以为这个牛x的引擎是日货,IT技术还是老美领先,这里是一个最近的pdf演讲稿关于TokuDB采用的Fractal Tree的详细介绍);当然,国货里面,姜承尧也很不错哦。Just joking here :P】
转载请注明:爱开源 » Innodb Crash Recovery恢复时间的飞跃