免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5045 | 回复: 0

InnoDB doublewrite与重做日志的关系 [复制链接]

论坛徽章:
1
数据库技术版块每日发帖之星
日期:2016-03-12 06:20:00
发表于 2013-07-25 17:02 |显示全部楼层
本帖最后由 qlks 于 2013-07-25 17:03 编辑

转自:http://insidemysql.blog.163.com/ ... 422013622114640256/

或许有人会觉得两者没有关系,但我可不是标题党,doublewrite的存在就是因为重做日志的关系。各位看官且听我慢慢分析就能知晓其中的利害关系。

doublewrite是为了解决页的partial write问题,即当一个页回刷回磁盘时,可能由于只回刷了一小部分,从而导致宕机恢复时可能出现的恢复失败的情况。Heikki Tuuri在bugs.mysql.com对doublewrite的历史有过一个说明,不过由于太过久远,我一时也未能找到该bug。简单来说,就是没有doublewrite时恢复可能会失败。

或许有DBA会问题,不是可以通过重做日志进行恢复吗?但是,问题就是在于InnoDB存储引擎的重做日志,因为其格式是physiological logging,而不是physical logging。网上看到有些朋友已经有对InnoDB的重做日志进行了一些分析,然而从我的角度看,他们都没有完全理解physiological logging。

根据每个数据库系统实现的不同,日志可分为以下几种类型:
  • physical logging
  • logical logging
  • physiological logging


physical logging是指在日志中保存一个页中发生改变的字节,也有称这种方式为old value-new value logging。通常来说,其数据结构可参考下面的实现:
  1. struct value_log{
  2.   int opcode;
  3.   long page_no;
  4.   long offset;
  5.   long length;
  6.   char old_value[length];
  7.   char new_value[length];
  8. };
复制代码
物理日志的好处是其记录的是页中发生变化的字节。这样重复多次执行该日志不会导致数据发生不一致的问题。也就是该日志是幂等的,没有partial write的问题。物理日志看起来很优雅,但其最大的问题是产生的日志量相对较大。例如对一个16K大小的页进行重新整理(reorganize),那么这时产生的日志就需要16K。此外,B+树分裂这类涉及到多个页修改的操作,产生的日志同样也会非常大。上次和达梦数据库的开发人员交流,得知达梦用的是该类型日志。

logical logging记录的是对于表的操作,这非常类似与MySQL数据库上层产生的二进制日志。由于是逻辑的,因此其日志的尺寸非常小。例如对于插入操作,其仅需类似如下的格式:
  1. <insert op, table name, record value>
复制代码
logical logging对于UNDO操作仅需对记录的日志操作进行逆操作。例如INSERT对应DELETE操作,DELETE对应INSERT操作。然而该日志的缺点同样非常明显,那就是在恢复时其可能无法保证数据的一致性。例如当对表进行插入操作时,表上还有其他辅助索引。当操作未全部完成时系统发生了宕机,那么要回滚上述操作可能是困难。因为,这时数据可能处在一个未知的状态。无法保证UNDO之后数据的一致性。

物理逻辑日志结合上述两种日志的优点。其设计思想是:physical-to-a-page, logical-within-a-page。即根据物理页进行日志记录,根据不同的逻辑操作类型进行日志的写入。在InnoDB存储引擎中,用户可以发现多种重做日志类型的定义。到MySQL 5.6版本时,共有51种不同类型的重做日志。此外,每个重做日志是有固定的头部格式,如:


可以看到redo_log_type定义了逻辑操作的类型,space,offset表示哪个物理页产生的日志。因此,InnoDB存储引擎的所有重做日志都是physiological logging的。对于页的整理操作,只需将redo_log_type设置为MLOG_PAGE_REORGANIZE,此时产生的日志仅10个字节(若space和offset可进行压缩,则可能会更小)。

另外,physiological logging页不是完全幂等的,这取决于重做日志类型。对于MLOG_PAGE_REORGANIZE类型的重做日志其是幂等的,但是对于INSERT产生的日志其不是幂等的,因为INSERT重做日志记录的不是插入的记录,而是待插入记录的前一条记录的位置,以及与该记录的二进制diff信息(这样做是为了进行压缩,从而使得重做日志更小)。因此,physiological logging的恢复还需要进行如下的判断:
  1. if page.lsn < log_record.lsn

  2.   redo(page,log);
复制代码
回到文章开头的问题,为什么需要doublewrite?现在问题很简单了,假设一个页在reorginaze后刷新到磁盘时发生了partial write的问题,那么由于重做日志中记录的仅仅是一个类型,没有原页的完整信息,因此恢复会失效。对于其他类型的重做日志,同样会存在这样的问题。即使是INSERT或者UPDATE操作产生的重做日志。

由于doublewrite的存在,页的刷新分为了两个步骤。虽然doublewrite的写入是顺序的,但是这对性能也产生了影响,特别是在写密集的应用环境中。ZFS在文件系统层解决了partial write的问题,并且ZFS的原生版本也已经移植到Linux,我会在下一个阶段对ZFS进行测试。另外,MariaDB 10.x版本计划支持Fusion-IO设备的atom write功能,因此可以通过设置参数skip-doublewrite禁用doublewrite,从而提高数据库的整体性能。Fusion-IO官方的说明是性能可以有50%的提升,不过个人持保留意见。待我测试后,再见分晓 InnoDB doublewrite与重做日志的关系 - insidemysql - Inside MySQL

– EOF –

PS:欢迎关注InsideMySQL公众帐号

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP