Mysql-两阶段提交

两阶段提交
前面我单独简述了 redolog 和 binlog 这两种日志的原理,相信你已经理解了。那当他们组合在一起使用的话会是什么样子的?如果你是 MySQL 的设计师,会先写 redolog 还是 binlog ?事实上无论是先写谁,都存在事务安全问题。我们来分析下吧。
- 先写 redolog 再写 binlog。
假设在写入 redolog 成功了,写入 binlog 的时候宕机了。服务恢复的时候,根据 redolog 数据恢复了,但是 binlog 中没有对应数据修改日志,出现两个日志数据不一致问题。
- 先写 binlog 再写 redolog。
假设在写入 binlog 成功了,写入 redolog 的时候宕机了。服务恢复的时候,但是 redolog 中没有对应数据修改日志,binlog 有记录。也出现两个日志数据不一致问题。
你可能会问两个日志不小心因为宕机造成数据不一致,不一致就不一致,有什么影响吗?影响还是很大的。binlog 在主从同步中起到关键作用,如果其中的数据缺失,会导致主从库的数据不一致。binlog还在数据恢复中起作用,如果其中的数据缺失,会导致数据恢复失败。redolog 在崩溃恢复时起关键作用,如果数据丢失,那所谓的崩溃恢复就不存在意义了。
那有什么办法能保证数据一致性?办法就是两阶段提交。
在 MySQL 中,Redo Log 用于记录数据页的物理变化,保证数据库崩溃恢复;Binlog 用于记录逻辑变更,用于主从复制和数据恢复。两阶段提交确保这两个日志的一致性,防止数据不一致。从而保证数据在发生故障时能够正确恢复。
- 以 update T set age=age+1 where ID=2; 这个更新语句来说。这条语句开启了自动提交事务。
- 首先 MySQL 执行器,会调用引擎的查询接口,查询 ID=2 这条记录。
- 如果记录在 buffer pool 中直接返回,否则要从磁盘中加载到 buffer pool 并返回。
- 执行器在内存中对数据做修改,即 age=age+1 。然后调用引擎的写接口。
- 引擎收到 age 的最新值,在 buffer pool 中更新对应的行数据。
- 引擎还会将更新对应的 redo log 写到 redo log buffer 中,并标记这条日志的状态为 prepare 。
- 引擎告诉执行器更新语句执完成了,可以随时提交这个更新事务了。
- 执行器收到通知后,完成 binlog 的写入,也是写到对应的 binlog buffer 中。
- 执行器写完 binlog 后,提交事务给引擎。
- 引擎把事务对应的 redo log 状态由 prepare 改成 commit,表示当前事务已提交。
以上就是 MySQL 的两阶段提交的流程。现在我们开分析下,它是如何保持一致性的。
假设在写入 binlog 时崩溃了,binlog 失败了,此时 redolog 的状态是 prepare 。MySQL 认为这种情况事务执行失败。在崩溃恢复中,会回滚该事务。
假设在提交事务时崩溃了,此时 redolog 状态是 prepare ,binlog 是完整的。MySQL 认为这种情况事务执行成功了,在崩溃恢复中,会根据 binlog 来提交事务,将 redolog 的状态由 prepare 改成 commit ,再恢复数据。
综上所述,两阶段提交能保证 Redo Log 和 Bin Log 的一致性。两阶段提交本质上就是将 Redo Log 拆分成了 prepare 和 commit 两种状态。