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

Inside MySQL

MySQL MariaDB InnoDB InnoSQL

 
 
 

日志

 
 
关于我

MySQL技术内幕系列作者, 网易杭州研究院MySQL技术经理, 擅长于MySQL performance tuning、troubleshooting、systems availability and scalability、capacity planning

网易考拉推荐

InnoDB doublewrite与重做日志的关系  

2013-07-22 16:28:30|  分类: InnoDB |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

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

doublewrite是为了解决页的partial write问题,即当一个页回刷回磁盘时,可能由于只回刷了一小部分,从而导致宕机恢复时可能出现的恢复失败的情况。Heikki Tuuribugs.mysql.comdoublewrite的历史有过一个说明,不过由于太过久远,我一时也未能找到该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
<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种不同类型的重做日志。此外,每个重做日志是有固定的头部格式,如:

InnoDB doublewrite与重做日志的关系 - insidemysql - Inside MySQL

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

另外,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%的提升,不过个人持保留意见。待我测试后,再见分晓 InnoDB doublewrite与重做日志的关系 - insidemysql - Inside MySQL

EOF –

PS:欢迎关注InsideMySQL公众帐号
InnoDB doublewrite与重做日志的关系 - insidemysql - Inside MySQL

  评论这张
 
阅读(1542)| 评论(5)
推荐 转载

历史上的今天

评论

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

页脚

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