mysql5.6 日志重做_InnoDB doublewrite与重做日志的关系

或许有人会觉得两者没有关系,但我可不是标题党,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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

struct

value_log{

int

opcode;

long

page_no;

long

offset;

long

length;

char

old_value[length];

char

new_value[length];

};

物理日志的好处是其记录的是页中发生变化的字节。这样重复多次执行该日志不会导致数据发生不一致的问题。也就是该日志是幂等的,没有partial write的问题。物理日志看起来很优雅,但其最大的问题是产生的日志量相对较大。例如对一个16K大小的页进行重新整理(reorganize),那么这时产生的日志就需要16K。此外,B+树分裂这类涉及到多个页修改的操作,产生的日志同样也会非常大。上次和达梦数据库的开发人员交流,得知达梦用的是该类型日志。

logical logging记录的是对于表的操作,这非常类似与MySQL数据库上层产生的二进制日志。由于是逻辑的,因此其日志的尺寸非常小。例如对于插入操作,其仅需类似如下的格式:

1

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种不同类型的重做日志。此外,每个重做日志是有固定的头部格式,如:

0818b9ca8b590ca3270a3433284dd417.png

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

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

1

2

3

if

page.lsn < log_record.lsn

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%的提升,不过个人持保留意见。待我测试后,再见分晓

0818b9ca8b590ca3270a3433284dd417.png

– EOF –

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值