0、基础知识and问题
从基础上我们了解:
(1)redolog作为数据库保证持久化的日志,在update事务提交后就会按一定的策略刷入磁盘中,在刷入后,即使数据库断电宕机,mysql也能从redolog中恢复数据到磁盘中,从而实现持久化。
(2)同样的,对于binlog,主要用于主从数据库之间的数据同步以及数据库的全数据恢复,常规的步骤是类似的:主库的update过程就会写binlog,提交后,就按照一定的策略刷入磁盘中。紧接着,在主从同步中,通过以下步骤发送给从库,从库通过读取中继日志实现主从的一致性。
(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 刷盘。
- 锁竞争激烈:两阶段提交虽然能够保证「单事务」两个日志的内容一致,但在「多事务」的情况下,却不能保证两者的提交顺序一致,因此,在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性,从而保证多事务的情况下,两个日志的提交顺序一致。