被面试官问住了,mysql 两阶段提交是什么鬼?-爱代码爱编程
1,前言
MySQL 通过两阶段提交的机制,保证了 redo log 和 bin log 的逻辑一致性,进而保证了数据的不丢失以及主从库的数据一致。
而说起两阶段提交,就不得不先介绍一下 redo log 和 bin log。
2,redo log
redo log 即重做日志,是 InnoDB 引擎特有的一种日志(有的面试官经常问到这一点)。
redo log 主要做什么呢?
以更新数据为例,我们知道,MySQL 的数据是存储在磁盘上的,如果每一次更新数据,都去磁盘寻址找到要更新的数据,进行更新操作的话,这个 IO 成本是非常高的。
如果是固态硬盘还好,如果是机械硬盘,那么 MySQL 的更新性能根本无法满足我们的业务需要。
所以,MySQL 采用了一种叫做 WAL 的技术,Write-Ahead Logging。
当更新数据时,将更新操作(即某个数据页上做了什么修改)先写到 redo log 里面,然后更新内存,这个更新操作就算完成了。MySQL 会在服务器空闲的时候,把 redo log 的操作记录刷新到磁盘里,以保持数据的一致性。
需要注意的是,redo log 虽然也是磁盘上的一个文件,但是由于操作是顺序写,所以性能是非常高的。
当然了,redo log 也是有大小上限的,不可能无限制的写入。
以上图为例,配置了 4 个 redo log,write pos 就是代表当前记录写到什么位置了,而 check point 表示一个推进点,它会不断的前移,做擦除数据的操作,以保证 redo log 可以不断的写入。
当然,擦除数据之前,会把 redo log 的记录刷新到磁盘。
通过 redo log,可以保证即使 MySQL 发生异常重启,数据也不会丢失(因为 redo log 是物理日志,可以进行重放),这个特性就叫做 crash-safe。
3,bin log
bin log 是 MySQL Server 提供的一种日志,叫做归档日志,所有引擎都可以使用 bin log。
那 bin log 和 redo log 的区别是什么呢?
1,这两种日志的提供者不同:bin log 是由 MySQL Server 提供的,redo log 是 InnoDB 引擎特有的。
2,redo log 主要记录的是某个数据页做了什么修改,bin log 记录的是语句的原始逻辑,比如更新了某一行的某个字段。
3,redo log 是循环写的,数据会被覆盖。bin log 是追加写,一个文件写满,就写下一个文件。
4,两阶段提交
介绍完了 redo log 和 bin log,我们再看一下他们两者是如何配合完成两阶段提交的。
上图就是一个更新数据的流程,可以看到,在更新一条数据之前,MySQL 会先将数据加载到内存,然后更新内存,开始写 redo log。
此时,redo log 处于 prepare 状态,等到 bin log 写完之后,再提交事务,这一条记录的更新操作就算完成了。
redo log prepare -> 写 bin log -> redo log commit,这个流程就叫做两阶段提交。
下面我们分析一下,采用两阶段提交的好处。
情景一,redo log 处于 prepare 状态时,如果写 bin log 失败了,那么更新失败,此时 redo log 没有 commit,bin log 也没有记录,两者的状态是一致的,没有问题。
情景二,redo log 处于 prepare 状态时,写 bin log 成功,但是宕机导致 commit 失败了。此时 bin log 产生了记录,redo log 没有写入成功,数据暂时不一致。
但是不用担心,当 MySQL 重启时,会检查 redo log 中处于 prepare 状态的记录。在 redo log 中,记录了一个叫做 XID 的字段,这个字段在 bin log 中也有记录,MySQL 会通过这个 XID,如果在 bin log 中找到了,那么就 commit 这个 redo log,如果没有找到,说明 bin log 其实没有写成功,就放弃提交。
通过这样的机制,保证了 redo log 和 bin log 的一致性。
5,总结
之所以 MySQL 中既存在 redo log,又存在 bin log,这是因为 bin log 是 MySQL Server 提供的一种归档日志,其本身并不具备 crash-safe 能力。而 redo log 本身不具备归档能力,他是一种循环写的日志。
MySQL 通过将这两种日志整合起来,并通过两阶段提交的机制,保证了数据的一致性。
写文不易,感谢您的点赞和关注。