MySQL中binlog和redo log的一致性问题

MySQL中binlog和redo log的一致性问题

本人目前在从事MySQL内核的开发和维护工作,以后会写一些MySQL的知识分享。
关于MySQL中binlog和redo log的一致性问题,在网上看过一些文章,感觉不是特别清楚,所以自己总结后和大家分享一下,文章如有问题,欢迎指教。

redo log 和 binlog

redo log

在MySQL InnoDB中,redo log是用来实现事务的持久性,即当事务在提交时,必须先将该事务的所有操作日志写到磁盘上的 redo log file进行持久化,这也就是我们常说的 Write Ahead Log 策略。有了redo log,在数据库发生宕机时,即使内存中的数据还没来得及持久化到磁盘上,我们也可以通过redo log完成数据的恢复,这样就避免了数据的丢失。

binlog

在MySQL中,binlog记录了数据库系统所有的更新操作,主要是用来实现数据恢复和主从复制的。一方面,主从配置的MySQL集群可以利用binlog将主库中的更新操作传递到从库中,以此来实现主从数据的一致性;另一方面,数据库还可以利用binlog来进行数据的恢复。

redo log 和 binlog的区别

  • redo log和binlog的产生方式不同。redo log是在物理存储引擎层产生,而binlog是在MySQL数据库的Server层产生的,并且binlog不仅针对InnoDB存储引擎,MySQL数据库中的任何存储引擎对数据库的更改都会产生binlog。
  • redo log和binlog的记录形式不同。MySQL Server层产生的binlog记录的是一种逻辑日志,即通过SQL语句的方式来记录数据库的修改;而InnoDB层产生的redo log是一种物理格式日志,其记录的是对于磁盘中每一个数据页的修改。
  • redo log和binlog记录的时间点不同。binlog只是在事务提交完成后进行一次写入,而redo log则是在事务进行中不断地被写入,redo log并不是随着事务提交的顺序进行写入的,这也就是说在redo log 中针对一个事务会有多个不连续的记录日志。

binlog和redo log的一致性问题

综上所述,binlog和redo log都是在事务提交阶段记录的。这时我们不禁会有一些疑问:

  • 是先写binlog还是先写redo log的呢?
  • 写binlog和redo log的顺序对于数据库系统的持久性和主从复制会不会产生影响?
  • 如果有影响,MySQL又是怎么做到binlog和redo log的一致性的呢?

带着这些问题,我深入地研究了MySQL中binlog和redo log的一致性问题。

先写binlog还是先写redo log的呢?

针对这个疑问,我们可以做出两个假设。

假设一:先写redo log再写binlog

想象一下,如果数据库系统在写完一个事务的redo log时发生crash,而此时这个事务的binlog还没有持久化。在数据库恢复后,主库会根据redo log中去完成此事务的重做,主库中就有可这个事务的数据。但是,由于此事务并没有产生binlog,即使主库恢复后,关于此事务的数据修改也不会同步到从库上,这样就产生了主从不一致的错误。

假设二:先写binlog再写redo log

想象一下,如果数据库系统在写完一个事务的binlog时发生crash,而此时这个事务的redo log还没有持久化,或者说此事务的redo log还没记录完(至少没有记录commit log)。在数据库恢复后,从库会根据主库中记录的binlog去回放此事务的数据修改。但是,由于此事务并没有产生完整提交的redo log,主库在恢复后会回滚该事务,这样也会产生主从不一致的错误。

通过上面的假设和分析,我们可以看出,不管是先写redo log还是先写binlog,都有可能会产生主从不一致的错误,那么MySQL又是怎么做到binlog和redo log的一致性的呢?

MySQL的内部XA(两阶段提交)

XA-2PC (two phase commit, 两阶段提交 )

XA是由X/Open组织提出的分布式事务的规范。XA规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口。XA为了实现分布式事务,将事务的提交分成了两个阶段:也就是2PC (tow phase commit),XA协议就是通过将事务的提交分为两个阶段来实现分布式事务。

  • prepare 阶段:第一阶段,事务管理器向所有涉及到的数据库服务器发出prepare"准备提交"请求,数据库收到请求后执行数据修改和日志记录等处理,处理完成后只是把事务的状态改成"可以提交",然后把结果返回给事务管理器.

  • commit 阶段:事务管理器收到回应后进入第二阶段,如果在第一阶段内有任何一个数据库的操作发生了错误,或者事务管理器收不到某个数据库的回应,则认为事务失败,回撤所有数据库的事务。数据库服务器收不到第二阶段的确认提交请求,也会把"可以提交"的事务回撤。如果第一阶段中所有数据库都提交成功,那么事务管理器向数据库服务器发出"确认提交"请求,数据库服务器把事务的"可以提交"状态改为"提交完成"状态,然后返回应答。

MySQL中的XA实现分为:外部XA和内部XA。前者是指我们通常意义上的分布式事务实现;后者是指单台MySQL服务器中,Server层作为TM(事务协调者),而服务器中的多个数据库实例作为RM,而进行的一种分布式事务,也就是MySQL跨库事务;也就是一个事务涉及到同一条MySQL服务器中的两个innodb数据库(因为其它引擎不支持XA)。

内部XA的额外功能

在MySQL内部,在事务提交时利用两阶段提交(内部XA的两阶段提交)很好地解决了上面提到的binlog和redo log的一致性问题:

  • 第一阶段: InnoDB Prepare阶段。此时SQL已经成功执行,并生成事务ID(xid)信息及redo和undo的内存日志。此阶段InnoDB会写事务的redo log,但要注意的是,此时redo log只是记录了事务的所有操作日志,并没有记录提交(commit)日志,因此事务此时的状态为Prepare。此阶段对binlog不会有任何操作。
  • 第二阶段:commit 阶段,这个阶段又分成两个步骤。第一步写binlog(先调用write()将binlog内存日志数据写入文件系统缓存,再调用fsync()将binlog文件系统缓存日志数据永久写入磁盘);第二步完成事务的提交(commit),此时在redo log中记录此事务的提交日志(增加commit 标签)。

可以看出,此过程中是先写redo log再写binlog的。但需要注意的是,在第一阶段并没有记录完整的redo log(不包含事务的commit标签),而是在第二阶段记录完binlog后再写入redo log的commit 标签。还要注意的是,在这个过程中是以第二阶段中binlog的写入与否作为事务是否成功提交的标志。

通过上述MySQL内部XA的两阶段提交就可以解决binlog和redo log的一致性问题。数据库在上述任何阶段crash,主从库都不会产生不一致的错误。

此时的崩溃恢复过程如下:

  1. 如果数据库在记录此事务的binlog之前和过程中发生crash。数据库在恢复后认为此事务并没有成功提交,则会回滚此事务的操作。与此同时,因为在binlog中也没有此事务的记录,所以从库也不会有此事务的数据修改。
  2. 如果数据库在记录此事务的binlog之后发生crash。此时,即使是redo log中还没有记录此事务的commit 标签,数据库在恢复后也会认为此事务提交成功(因为在上述两阶段过程中,binlog写入成功就认为事务成功提交了)。它会扫描最后一个binlog文件,并提取其中的事务ID(xid),InnoDB会将那些状态为Prepare的事务(redo log没有记录commit 标签)的xid和Binlog中提取的xid做比较,如果在Binlog中存在,则提交该事务,否则回滚该事务。这也就是说,binlog中记录的事务,在恢复时都会被认为是已提交事务,会在redo log中重新写入commit标志,并完成此事务的重做(主库中有此事务的数据修改)。与此同时,因为在binlog中已经有了此事务的记录,所有从库也会有此事务的数据修改。

总结

上述利用两阶段提交解决了事务提交时binlog和redo log的一致性问题,此过程的实现是在MySQL 5.6 之前。但是此过程存在严重缺陷:此过程中为了保证MySQL Server层binlog的写入顺序和InnoDB层的事务提交顺序是一致的,MySQL数据库内部使用了prepare_commit_mutex这个锁。但是在启用了这个锁之后,并不能并发写入binlog,从而导致了group commit失效。这个问题在MySQL 5.6中的Binary Log Group Commit(BLGC)得到解决。

参考

《MySQL技术内幕 InnoDB存储引擎》----姜承尧
MySQL binlog 组提交与 XA(两阶段提交)
MySQL 中Redo与Binlog顺序一致性问题

https://blog.csdn.net/u014710633/article/details/89839443

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值