基于Redo log & Undo log的MySQL的崩溃恢复
Redo log Undo log
Redo log 重做日志,记录,修改过的数据
Undo log 回滚日志,记录修改之前的数据
两个我不做详细的介绍了,redo log就是记录哪些地方被修改了
undo log是记录修改之前我们的数据长什么样
更新流程
我们来捋一下这个流程,首先是更新数据,会先去Buffer Pool中查找是否有这个页,如果说不存在这个页,就会从磁盘中加载,也就是第二步
第三步,有了这个页,我们需要先写Undo log,在一切开始之前,先记录没动过的样子
第四步,就是更新数据,先是写入Redo log Buffer中,因为一个事务中不止一个修改的地方,所以先写道Redo log Buffer中,一并写入到Redo log 文件中去
然后是写Binlog文件
其中有几点我们需要继续探讨
为什么要写入Redo log buffer中?我们修改完页,为什么不直接刷入到磁盘中去
这个问题很好理解,为什么修改之后,不直接刷入到磁盘去呢?因为这样子做,效率太低了,我们要刷入到磁盘的化,肯定是以页为单位的,一个页是16kb,而且还是随机IO,那样写的太慢了,我么redo log 文件,是顺序IO,性能快,而且不是完整的页
占用内存小,又快,肯定写到buffer中去,然后写到redo log file文件中啊
两阶段提交
binlog的一致性问题出现
你可能听过两阶段提交,就是为了解决binlog的一致性问题的
我们来想想,怎么会出现这个问题
刷盘的目的,无非就是两个目的,redo log写到磁盘中去,binlog写到磁盘中去
那无非就有两种方案
第一,先写redo log ,再写binlog
第二,先写bin log,再写redo log
第一种方案:
先写了redo log,bin log 还没写,MySQL宕机,redo log刷入了磁盘,bin log没有这条记录,此时bin log就丢失了记录,出现一致性问题
第二种方案:
先写bin log,redo log还没写,MySQL宕机,此时redo log没写,那么重启的时候,binlog 和redo log又不一样实际的数据又会丢失
所以我们必须保证一个事情,binlog 和 Redo log 必须保持一致性!!
为了这个目标就有两阶段提交,也就是2PC(two-phase commit protocool)
基于2PC
为了保证事务的一致性,所以就出现了2PC,它将事务的提交分成了两个不部分Prepare和Commit/Rollback
Prepare阶段,首先我们从Redo log Buffer种将Redo Log写入文件,然后刷入磁盘,记录上内部的XA事务的ID,同时将Redo log设置为Prepare状态,Redo log写入成功,再将Binlog同样刷入磁盘,记录XA事务的ID
Commit阶段,向磁盘种的Redo log写入Commit标识,表示事务提交,然后执行器调用存储引擎的接口提交事务.
验证
我们来验证两阶段提交是否可以保证一致性
首先,假设Redo log 刷入成功,但是还没来得及刷入Binlog,此时宕机,重启之后发现Redo log 没有commit标志,那么就会根据记录的XA事务Id找到这个事务,然后回滚
如果Redo log刷入成功,Binlog也刷入成功,还没来得及将Redo log从Prepare改成Commit,MySQL宕机,重启之后,发现虽然Redo log虽然没有commit标志,但是通过XA事务ID查询到的Binlog已经刷入到磁盘中去了额,此时MySQL也会提交事务
我比较困惑的时候,如果Redo log刷入盘了,打上了Prepare标志,但是写Binlog写到一半的时候,突然MySQL宕机了,此时还会有一致性问题,这里我先放下,之后我懂了再来更新这里的问题