2

突然掉电,为啥MySQL也不会丢失数据?

 2 years ago
source link: https://www.51cto.com/article/706933.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
突然掉电,为啥MySQL也不会丢失数据?-51CTO.COM
突然掉电,为啥MySQL也不会丢失数据?
作者:架构师之路 2022-04-19 16:44:19
MySQL采用buffer机制,避免每次读写进行磁盘IO,提升效率,那么,问题来了,这个操作并非原子,如果执行到一半断电,会不会出现问题呢?

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

e883a5028e8c4328001299753ae922098e0733.jpg

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

43a144494d39c3d39ac432e7877a04c95657d9.png

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

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

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

d5e2c7586563056fb114755e9889d69027e259.png

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

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

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

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

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

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

13ac3f498bff9dc107e0216323de61e2306899.gif252c8c2487803866898146bda3f997f2aeefeb.png

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

  • 第一步:页数据先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修复页数据的图。

23d0963989e7ac57d5e277b843467b3902141b.png

可以看到,启动过程中:

  • InnoDB检测到上一次为异常关闭;
  • 尝试恢复ibd数据,失败;
  • 从DWB中恢复写了一半的页;

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

分析DWB执行的三个步骤:

  • 第一步,页数据memcopy到DWB的内存,速度很快;
  • 第二步,DWB的内存fsync刷到DWB的磁盘,属于顺序追加写,速度也很快;
  • 第三步,刷磁盘,随机写,本来就需要进行,不属于额外操作;

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

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

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

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

  • Innodb_dblwr_pages_written:记录写入DWB中页的数量。
  • Innodb_dblwr_writes:记录DWB写操作的次数。

可以通过:

show global status like "%dblwr%"

来进行查询。

d29aae985cd420f952d3991b48c8839e044137.png

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

  • 在异常崩溃时,如果不出现“页数据损坏”,能够通过redo恢复数据;
  • 在出现“页数据损坏”时,能够通过double write buffer恢复页数据;

double write buffer:

  • 不是一个内存buffer,是一个内存/磁盘两层的结构,是InnoDB里On-Disk架构里很重要的一部分;
  • 是一个通过写两次,保证页完整性的机制;

知其然,知其所以然。

思路比结论重要,希望大家有收获。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK