**Mysql 的 innoDB 存储引擎是怎么实现数据持久化的?二**

上一篇写了 Buffer Pool,Buffer Pool 确实是能提升读写效率。不过内存中的数据一断电就消失了,并不是真的持久化了。

这时候就需要 redo log 来保证数据的持久化。也就是 ACID 中的 D 属性。


问题

redo log 是怎么保证数据持久化的呢?

为什么不直接持久化数据,而要持久化 redo log?

checkpoint

第一个问题,简单来讲就是每次 update、insert、detele 语句,在 Buffer Pool 中修改的同时,会在 redo log 中写一条记录并持久化下来。

这就很奇怪,为什么一样反正都是持久化,为什么非要持久化 redo log而不是直接持久化数据呢?

每次 update、insert、detele 的数据行都不一定在同一个扇区,可以想象一下,直接持久化数据的话,磁盘的磁针(对于机械硬盘而言)应该就是每次修改都要转来转去,也就是随机 IO,那效率是极低的。

而 InnoDB 的 redo log 在设计时就尽量保持 Redo Log 存储在一段连续的空间上,因此在系统第一次启动时就会将日志文件的空间完全分配,以顺序追加的方式记录 Redo Log,这种顺序 IO相比上面的随机 IO效率高了不少。

类似 Buffer Pool,redo log 也有一个 redo log buffer 区域,也是在内存中。那么 redo log buffer 是怎么怎么保证信息在崩溃的时候不会丢失呢?

这是由一个参数innodb_flush_log_at_trx_commit控制的,该参数有 0,1,2 三个值可选,默认是 1。

0:事务提交会写在 redo log buffer 中,然后每秒钟写入操作系统缓存并调用fsync()刷到磁盘。(这里有个用户态和内核态的概念,如下图,在类 unix 系统中的默认实现是调用fsync()
1:默认值,每次提交事务向磁盘同步 redo log。
2:每次提交事务将 redo log 写到操作系统的缓冲区中,然后每秒钟调用fsync()刷到磁盘。

**Mysql 的 innoDB 存储引擎是怎么实现数据持久化的?二**

这里系统调用 fsync()也不是固定的,在不同的操作系统上都有多种不一样的解决方式,Mysql 官网上给出的就有以下几种。

**Mysql 的 innoDB 存储引擎是怎么实现数据持久化的?二**

那持久化之后的 redo log,那么多日志,究竟从哪里开始是没有持久化的,哪里是已经持久化的呢?
这就依赖着checkpoint,Mysql 采用 redo log 可以理解为写数据文件是"异步"的,写日志文件是"同步"的。

数据库实例崩溃时,内存中的 Buffer Pool 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复 Buffer Pool 中的数据状态,并确保已经提交的数据被写入到数据块中。checkpoint 是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。

可以理解为数据库重启时在 redo log 的checkpoint之后开始恢复数据,而 redo log 是一个环,checkpoint之前区域又可以被覆盖以重新利用。


才疏学浅,理解不到位、有误的地方欢迎大佬们指正!

扫码关注峡谷程序员!
**Mysql 的 innoDB 存储引擎是怎么实现数据持久化的?二**