文章目录
- 为什么需要两阶段提交?
- 两阶段提交流程?
- 两阶段提交缺点?
为什么需要两阶段提交?
为了保证事务的持久性和一致性,MySQL需要确保redo log和binlog的同步持久化。MySQL通过“两阶段提交”的机制来实现在事务提交时,这两个日志必须保持一致,以避免出现数据不一致的问题。
为什么会出现日志不一样的这种情况?因为事务提交后,redo log 和 binlog 都要持久化到磁盘,但是这两个是独立的逻辑,可能出现半成功的状态。
即,有可能redo持久化了,但是binlog没持久化;或者是redo没有持久化成功,而binlog持久化成功了。这样就会导致它们两个日志的不一致性。
而我们通过“两阶段提交”的机制来保证日志一致的问题。
两阶段提交流程?
- 准备阶段(Prepare):
在事务执行过程中,所有的数据更改都会先记录到InnoDB存储引擎的redo log中,此时事务处于prepare阶段。此阶段确保了即使发生崩溃,更改也能通过redo log进行恢复。
在准备阶段结束时,InnoDB会生成一个唯一的事务ID(XID)。InnoDB会将一个包含此XID和事务状态的特殊标记记录写入redo log,并将redo log标记为prepare状态。 - 写入binlog:
事务的所有更改都会记录到binlog中,然后记录一个包含XID的COMMIT事件。 - 写binlog到磁盘:
MySQL会将binlog的内容从内存缓冲区通过write操作写入文件缓冲区,随后根据配置(例如,sync_binlog=1)可能会立即刷盘到磁盘,以确保binlog的持久性。 - 提交阶段(Commit):
在binlog成功写入磁盘后,事务会进入提交阶段。此时,InnoDB会使用前面生成的XID标记为已提交(Committed),并将这个提交操作记录到redo log中。
最后,InnoDB会根据需要将redo log的更改刷盘到磁盘上,完成事务的持久化。此时,事务正式提交完成。
图片来源:小林coding
两阶段提交缺点?
磁盘 I/O 次数高:对于“双1”配置,每个事务提交都会进行两次 fsync(刷盘),一次是 redo log 刷盘,另一次是 binlog 刷盘。
锁竞争激烈:两阶段提交虽然能够保证「单事务」两个日志的内容一致,但在「多事务」的情况下,却不能保证两者的提交顺序一致,因此,在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性,从而保证多事务的情况下,两个日志的提交顺序一致。