两阶段提交:详解数据库宕机引起的主从不一致问题、redolog与binlog的两阶段提交

0、基础知识and问题

        从基础上我们了解:

        (1)redolog作为数据库保证持久化的日志,在update事务提交后就会按一定的策略刷入磁盘中,在刷入后,即使数据库断电宕机,mysql也能从redolog中恢复数据到磁盘中,从而实现持久化。
        (2)同样的,对于binlog,主要用于主从数据库之间的数据同步以及数据库的全数据恢复,常规的步骤是类似的:主库的update过程就会写binlog,提交后,就按照一定的策略刷入磁盘中。紧接着,在主从同步中,通过以下步骤发送给从库,从库通过读取中继日志实现主从的一致性。
两阶段提交:详解数据库宕机引起的主从不一致问题、redolog与binlog的两阶段提交_第1张图片
       (3)对于undolog,会在开启事务,update更新之前先记录相应的旧值,方便事务的回滚。

问题: 

现在有一个问题:由于RedoLog和BinLog的刷盘过程是相互独立的两个过程,那么在主从同步的过程中,如果发生数据库宕机:如果RedoLog日志或者BinLog日志的其中之一成功刷盘,而另一个没有成功(由于相互独立,这是有可能发生的),那么就会发生以下情况: 

  • 如果在将 redo log 刷入到磁盘之后, MySQL 突然宕机了,而 binlog 还没有来得及写入。            MySQL 重启后,通过 redo log 能将数据字段恢复到新值
            但是 binlog 里面没有记录这条更新语句,在主从架构中,binlog 会被复制到从库,由于 binlog 丢失了这条更新语句,从库的这字段是旧值,与主库的值不一致性
  • 如果在将 binlog 刷入到磁盘之后, MySQL 突然宕机了,而 redo log 还没有来得及写入
            由于 redo log 还没写,崩溃恢复以后这个事务无效,所以数据字段还是旧值
            而 binlog 里面记录了这条更新语句,在主从架构中,binlog 会被复制到从库,从库执行了这条更新语句,那么字段是新值,与主库的值不一致性;

        那么该如何在断电宕机情况下保证主从的一致性呢?
        即 数据库的两阶段提交策略。

1、 两阶段提交的具体过程

         两阶段,就是让redolog分为两阶段提交,因为redolog的操作可以撤销,通过一个MySQL 内部开启一个 XA 事务(注意,这个事务是一个宏观上的大事务,而不是sql语句组成的事务)分两阶段来完成 XA 事务的提交,来保证redolog和binglog两个日志的刷盘,这两个任务的原子性。

        具体来说,redolog的提交,分为了prepare阶段和commit阶段:
        (1)prepare阶段,将redolog的事务状态设为prepare、将事务XID写入redo log,并把redo log持久化到磁盘中

        (2)commit阶段:把事务XID写入binlog,并把binlog刷盘,然后将redo log事务状态设置为commit

         我们发现,实际上这个过程的核心,是通过日志的事务ID来判断是否完成某个步骤的,例如在这样的过程下,如果出现异常,是如何保证双方的一致性呢?

        断电后,在 MySQL 重启后会按顺序扫描 redo log 文件,碰到处于 prepare 状态的 redo log,就拿着 redo log 中的 XID 去 binlog 查看是否存在此 XID:

  • 如果redolog都刷盘失败,那就全都回滚!
  • 如果 binlog 中没有当前内部 XA 事务的 XID,说明虽然redolog 完成刷盘,但是 binlog 还没有刷盘,则回滚整个 XA事务。(因为有undolog,所以可以回滚提交了的redolog)
  • 如果 binlog 中有当前内部 XA 事务的 XID,说明 redolog 和 binlog 都已经完成了刷盘,则提交事务
  • 如果redolog都是commit状态了,那更没问题了!

2、个人思考 

         在学习的过程中我在思考一个问题,为什么两阶段提交,要让redolog分两阶段,而不是让binlog分成两阶段提交呢?
        和同学探讨请教后发现,是因为,两阶段提交的redolog,即使redolog刷盘了,如果binlog没刷盘,我就让两个事情都回滚就好了,对主从数据不会有任何影响。
        但是如果让binlog两阶段提交,如果binlog刷盘成功了、而redolog刷盘失败,由于binlog刷盘一成功就会进行主从复制,从数据库的数据已经被刷盘了,此时虽然redolog失败、我想把整个大事务rollback,但由于已经把binlog同步给从数据库,已然无力回天。
        实在是豁然开朗啊。

 3、两阶段提交的弊端

  • 磁盘 I/O 次数高:对于“双1”配置,每个事务提交都会进行两次 fsync(刷盘),一次是 redo log 刷盘,另一次是 binlog 刷盘。
  • 锁竞争激烈:两阶段提交虽然能够保证「单事务」两个日志的内容一致,但在「多事务」的情况下,却不能保证两者的提交顺序一致,因此,在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性,从而保证多事务的情况下,两个日志的提交顺序一致。

你可能感兴趣的:(数据库,java,开发语言,binlog,redolog,分布式)