MySQL崩溃恢复流程
Buffer Pool是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子。
1、黑盒下的更新数据流程
当我们查询数据的时候,会先去Buffer Pool中查询。如果Buffer Pool中不存在,存储引擎会先将数据从磁盘加载到Buffer Pool中,然后将数据返回给客户端;同理,当我们更新某个数据的时候,如果这个数据不存在于Buffer Pool,同样会先数据加载进来,然后修改修改内存的数据。被修改过的数据会在之后统一刷入磁盘。
MySQL 奔溃恢复:
这个过程看似没啥问题,实则不讲武德。假设我们修改Buffer Pool中的数据成功,但是还没来得及将数据刷入磁盘MySQL就挂了怎么办?按照上图的逻辑,此时更新之后的数据只存在于Buffer Pool中,如果此时MySQL宕机了,这部分数据将会永久的丢失;
再者,我更新到一半突然发生错误了,想要回滚到更新之前的版本,该怎么办?那不完犊子吗,连数据持久化的保证、事务回滚都做不到还谈什么崩溃恢复?
2、Redo Log & Undo Log
而通过MySQL能够实现崩溃恢复的事实来看,MySQL必定实现了某些骚操作。没错,这就是接下来我们要介绍的另外的两个关键功能,Redo Log和Undo Log。
这两种日志是属于InnoDB存储引擎的日志,和MySQL Server的Binlog不是一个维度的日志。
(1)Redo Log 记录了此次事务「完成后」的数据状态,记录的是更新之「后」的值
(2)Undo Log 记录了此次事务「开始前」的数据状态,记录的是更新之「前」的值
所以这两种日志有明显的区别,我用一种更加通俗的例子来解释一下这两种日志。
Redo Log就像你在命令行敲了很长的命本文来源gao@daima#com搞(%代@#码网令,敲回车执行,结果报错了。此时我们只需要再敲个↑就会拿到上一条命令,再执行一遍即可。
Undo Log就像你刚刚在Git中Commit了一下,然后再做一个较为复杂的改动,但是改着改着你的心态崩了,不想要刚刚的改动了,于是直接git reset --hard $lastCommitId
回到了上一个版本。
3、实现日志后的更新流程
有了Redo Log和Undo Log,我们再将上面的那张图给完善一下。
MySQL 崩溃恢复:
首先,更新数据还是会判断数据是否存在于Buffer Pool中,不存在则加载。上面我们提到了回滚的问题,在更新Buffer Pool中的数据之前,我们需要先将该数据事务开始之前的状态写入Undo Log中。假设更新到一半出错了,我们就可以通过Undo Log来回滚到事务开始前。