MySQL 突然掉电为什么不丢数据?double write buffer(29/38)

16K 的页要写 4 个 4K 的文件系统页,写一半断电怎么办——写两次,总有一个地方的数据是 OK 的

数据库内核实践第 29 课封面:数据库内核29:MySQL 突然掉电为什么不丢数据?double write buffer

16K 的页要写 4 个 4K 的文件系统页,写一半断电怎么办——写两次,总有一个地方的数据是 OK 的

《数据库内核原理》第 29 篇:double write buffer 与页数据损坏。

MySQL采用buffer机制,避免每次读写进行磁盘IO,提升效率:

第 24 篇《InnoDB 缓冲池 buffer pool:LRU 的两次改良》

第 25 篇《InnoDB 写缓冲 change buffer:写请求怎么免磁盘 IO?》

第 28 篇《MySQL 事务已提交,数据却丢了?检查 innodb_flush_log_at_trx_commit》

MySQL的buffer一页的大小是16K,文件系统一页的大小是4K,也就是说,MySQL将buffer中一页数据刷入磁盘,要写4个文件系统里的页。

MySQL 一页 16K 对应文件系统 4 个 4K 的页

如上图所示,MySQL里page=1的页,物理上对应磁盘上的1+2+3+4四个格。

那么,问题来了,这个操作并非原子,如果执行到一半断电,会不会出现问题呢?

会,这就是所谓的“页数据损坏”。

页数据损坏:刷了 3 个文件系统页就掉电,数据完整性被破坏

如上图所示,MySQL内page=1的页准备刷入磁盘,才刷了3个文件系统里的页,掉电了,则会出现:重启后,page=1的页,物理上对应磁盘上的1+2+3+4四个格,数据完整性被破坏。

redo无法修复这类“页数据损坏”的异常,修复的前提是“页数据正确”并且redo日志正常。

如何解决这类“页数据损坏”的问题呢?

很容易想到的方法是,能有一个“副本”,对原来的页进行还原,这个存储“副本”的地方,就是Double Write Buffer。

Double Write Buffer,但它与传统的buffer又不同,它分为内存和磁盘的两层架构。

传统的buffer,大部分是内存存储;而DWB里的数据,是需要落地的。

Double Write Buffer 两层架构:页数据先 memcopy 到 DWB 内存,再刷 DWB 磁盘,最后刷数据磁盘

如上图所示,当有页数据要刷盘时:

页数据先memcopy到DWB的内存里

DWB的内存里,会先刷到DWB的磁盘上

DWB的内存里,再刷到数据磁盘存储上

DWB由128个页构成,容量只有2M。

步骤2和步骤3要写2次磁盘,这就是“Double Write”的由来。

DWB为什么能解决“页数据损坏”问题呢?

假设步骤2掉电,磁盘里依然是1+2+3+4的完整数据。

只要有页数据完整,就能通过redo还原数据。

假如步骤3掉电,DWB里存储着完整的数据。

所以,一定不会出现“页数据损坏”问题。

写了2次,总有一个地方的数据是OK的。

自己实验了几十次,仍没能复现“页数据损坏”,在网上找了一个“页数据损坏”时,MySQL重启过程利用DWB修复页数据的图。

MySQL 重启过程利用 DWB 修复写了一半的页的启动日志截图

可以看到,启动过程中:

(1)InnoDB检测到上一次为异常关闭;

(2)尝试恢复ibd数据,失败;

(3)从DWB中恢复写了一半的页;

能够通过DWB保证页数据的完整性,但毕竟DWB要写两次磁盘,会不会导致数据库性能急剧降低呢?

分析DWB执行的三个步骤:

(1)第一步,页数据memcopy到DWB的内存,速度很快;

(2)第二步,DWB的内存fsync刷到DWB的磁盘,属于顺序追加写,速度也很快;

(3)第三步,刷磁盘,随机写,本来就需要进行,不属于额外操作;

另外,128页(每页16K)2M的DWB,会分两次刷入磁盘,每次最多64页,即1M的数据,执行也是非常之快的。

综上,性能会有所影响,但影响并不大。

(1)write-ahead-log之所以性能高,就是因为顺序追加写;(2)有第三方测评,评估约10%性能损失;

更具体的,InnoDB里有两个变量可以查看double write buffer相关的情况:

Innodb_dblwr_pages_written

记录写入DWB中页的数量。

Innodb_dblwr_writes

记录DWB写操作的次数。

可以通过:

show global status like "%dblwr%"

来进行查询。

show global status like 「%dblwr%「 查询结果截图

结尾

MySQL有很强的数据安全性机制:

(1)在异常崩溃时,如果不出现“页数据损坏”,能够通过redo恢复数据;

(2)在出现“页数据损坏”时,能够通过double write buffer恢复页数据;

double write buffer:

(1)不是一个内存buffer,是一个内存/磁盘两层的结构,是InnoDB里On-Disk架构里很重要的一部分;

(2)是一个通过写两次,保证页完整性的机制;

希望大家有收获。

相关文章:

第 24 篇《InnoDB 缓冲池 buffer pool:LRU 的两次改良》

第 25 篇《InnoDB 写缓冲 change buffer:写请求怎么免磁盘 IO?》

第 28 篇《MySQL 事务已提交,数据却丢了?检查 innodb_flush_log_at_trx_commit》

检验一下

检索练习 · 页数据损坏

为什么会出现「页数据损坏」?

检索练习 · DWB 三步

有页数据要刷盘时,Double Write Buffer 的三个步骤是?

检索练习 · 性能影响

DWB 写两次磁盘,为什么性能影响不大?

检索练习 · 观测变量

如何查看 double write buffer 写入的页数量和写操作次数?

double write buffer 保证页完整,redo log 保证已提交事务不丢——那 redo log 里到底记了什么格式、LSN 又怎么用?下一篇:redo log、LSN 与 PXB 在线热备原理。

知其然,知其所以然。思路比结论更重要。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

京ICP备2025137728号-3