IT技术博客大学习 共学习 共进步

Innodb Crash Recovery恢复时间的飞跃

SQL部落 2011-07-14 23:49:52 浏览 3,581 次

之前没经历过漫长的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 #29847Bug #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;当然,中国也有例如:姜承尧。

建议继续学习

  1. Innodb IO优化-配置优化 (阅读 7,603)
  2. Innodb分表太多或者表分区太多,会导致内存耗尽而宕机 (阅读 7,565)
  3. Innodb 表和索引结构 (阅读 6,041)
  4. InnoDB线程并发检查机制 (阅读 5,601)
  5. Innodb如何使用内存 (阅读 5,101)
  6. Innodb文件表空间结构 (阅读 5,063)
  7. 快速预热Innodb Buffer Pool的方法 (阅读 4,982)
  8. InnoDB的缓存替换策略及其效果 (阅读 4,781)
  9. 多版本并发控制:PostgreSQL vs InnoDB (阅读 4,561)
  10. InnoDB之Dirty Page、Redo log (阅读 4,481)