InnoDB 存储引擎之 Double Write Buffer

发布时间 2023-11-02 16:26:25作者: 变体精灵

一、概述

InnoDB 默认 page 页大小为 16KB,Linux 操作系统文件交互的最小单位是 4KB,而磁盘的最小交互单位是扇区,大小一般为 512B

假设 InnoDB 存储引擎在向磁盘写入数据时,Mysql 服务器突然宕机,那么就有可能只有一部分数据页写入到磁盘,另外一部分数据发生丢失,这种情况称为 部分写失效

这个时候你可能会说,我们不是有 redo log 吗,使用 redo log 重放就可以进行数据恢复了,但是千万别忘记了,redo log 是物理日志,它记录了 aaa 表空间 bbb 表 ccc 偏移量处做了 ddd 修改,如果数据页已经损坏了,使用 redo log 对该损坏的数据页进行重做是没有意义的

基于上述原因,InnoDB 引入了 Double Write Buffer

下面是写失效的图示

 

二、什么是 Double Write Buffer

Double Write Buffer 分为两个部分,一部分在内存中,大小为 2MB,另外一部分在系统表空间中,存储连续,大小也为 2MB,分为两个小区,总共有 128 个数据页

Double Write 可以理解为一个副本,在发生写失效时,先从 Double Write Buffer 中找到损坏的数据页的副本,将该副本替换掉表空间(.ibd)中损坏的数据页,修复好了损坏的数据页之后,再利用 redo log 进行重做,这样数据就不会丢失

 

三、Double Write Buffer 工作原理

1、当进行缓冲池中的脏页刷新到磁盘的操作时,并不会直接写磁盘,每次脏页刷新必须要先写 Redo Log Buffer

2、通过 memcpy(memory copy)函数将脏页复制到内存中的 Double Write Buffer 中

3、Double Write Buffer 再分两次,每次 1MB 顺序写入共享表空间的物理磁盘上,这就是第一次写(注意: 磁盘上系统表空间里的 Double Write Buffer 是一块连续的区域,写入时是顺序写,性能比较好)

4、在完成 Double Write Buffer 磁盘的写入后,再将 Double Write Buffer 中的页写入各个表对应的独立表空间文件中(数据文件.ibd),这就是第二次写

假设在 step 1、step2 过程中失败了,由于数据还是在内存中的操作,没有落磁盘,丢失了就丢失了,没有影响

假设在 step 3 的时候 Linux 服务器宕机了,只有部分的页写入了磁盘上的 Double Write Buffer,此时可以通过比对 系统表空间 和 独立表空间的数据页,发现 系统表空间的数据页发生了损坏,但是独立表空间 .ibd 文件上的数据页是完整的,可以将独立表空间中完整的数据页读入内存,然后使用 redo log 进行重做

假设在 step 4 的时候Linux 服务器宕机了,导致独立表空间 .ibd 文件上的数据页部分失效,但是由于系统表空间 Double Write Buffer 上的数据页是完整的,可以找到最近一个版本的 Double Write Buffer 副本,将其复制到 xxx.ibd 的数据页上,让数据页完整,然后使用 redo log 进行重做即可

相比于 dirty page 直接写 xxx.ibd 文件,增加了 Double Write Buffer 之后,会多一次的写磁盘操作,但是由于系统表空间内的 Double Write Buffer 是连续存储的,属于顺序写,性能损耗不会很大,更重要的是 Double Write Buffer 可以保证数据页的安全可靠性

注意: 我们只要有完整的数据页和 redo log 就可以利用 redo log 进行重放,从而保证数据页的可靠性(重做的前提是数据页要完整)