MySQL的Double Write如何保证可靠性?

前言

📚 全文字数 : 6k

⏳ 阅读时长 : 8min

📢 关键词 : Redis持久化、AOF重写、Swap、fork子进程

在之前对MySQL的知识总结的时候,我们知道了MySQL基本单位是数据页,默认情况下每个数据页的大小是16kb。数据页被读取到内存(Buffer Pool)中后被称为缓存页, 当对Buffer Pool中的数据页做了更新后,此时的数据页叫做:脏页,脏页最终是要刷入磁盘的,那么问题来了。

当数据页写入磁盘时,此时突然断电宕机了,数据只写入了一部分,数据丢失了吗? partial page write(部分页面写入)是啥,来电重启怎么恢复?

上面两个问题存在于这种场景:当把一个16K大小的数据页写入到磁盘中时,结果刚写了8k,突然断电机器宕机了,那此时只有一部分是写入成功的,这种情况就叫partial page write(部分页面写入)。

因为你想啊,MySQL的数据页默认是16K,而文件系统的数据页是4K,磁盘IO的最小单位是512字节,出现宕机很大可能磁盘中只有一部分写入成功,因为数据页写入到文件系统中需要经历 (16/4) 4次物理写。

而InnoDB的 Double Write就时用来解决partial page write问题的,具体怎么解决的,我们一探究竟。

Double Write是啥

为了解决文章开头中描述的问题,MySQL引入了double write这个特性,它针对的是脏数据(脏页),提高innodb的可靠性,用来解决部分写失败(partial page write)的问题。

我们知道被修改的数据最终是要输入到磁盘中的,为什么叫 double write呢,字面上可理解为两次写入的意思。对的,double write 刷盘是将一份脏数据写到共享【共享表空间 ibdata】中,一份写到真正的【数据文件 ibd】永久的保存,所以就叫double wriete。此时double write中存在副本,可以直接覆盖到ibd中对应的页中 。

Double Write写入流程

添加图片注释,不超过 140 字(可选)

我们可以看到 Double Write)由两部分组成:内存中的 Double Write Buffer 和 磁盘上的 ibdata1的两个区(连续的128页,2M大小)

具体的实现步骤如下:

  1. 用户修改过得数据页(脏页)先Copy到Double Write Buffer中
  2. 然后从Double Write Buffer 中以1MB大小顺序写入磁盘中的【共享表空间 ibdata】(因为该空间维护的是128个连续页,最小16KB,所以不会出现部分写失效情况)
  3. 再写入到磁盘的【数据文件 ibd】

是的,一切看起来都是那么的合乎逻辑,但是这里有几个问题,写Double Write 时候Crash了怎么办?写ibd时Crash了怎么办?

嗯,带着这些问题,继续往下看!

崩溃场景和恢复

1:写Double Write 的时候Crash了怎么办?

在Double Write Buffer写Double Write是Crash掉了,此时ibd还是原始干净数据,因为还没从Double Write Buffer写到ibd呢。

其实还有Redo Log文件,服务重启动后通过redo进行恢复 ,因为Redo Log是在修改数据页前完成的(WAL:预写日志),即DB需要保证Redo Log先完整安全地落盘,然后才能去修改对应的数据页(先在内存Buffer Pool上修改修改)。

此时根据Redo Log文件向缓存池中加载数据页,通过比较Redo Log与数据页的LSN大小 redo log lsn > page lsn,来更新数据页,更新完成后该数据页为脏页,然后再讲脏页复制到Double Write Buffer,重复上面写入原理的步骤。

我们将上面Double Write的原理图再完善一点,整个恢复过程如下:

添加图片注释,不超过 140 字(可选)

2:写ibd时Crash了怎么办?

写ibd时发生crash,因此此时Double Write中存在副本,可以直接覆盖到ibd中对应的页中,然后再继续redo恢复。

3:为何需要Double Write?有Redo Log还不够吗?

我们知道Redo Log是被MySQL设计为异常崩溃恢复的,Double Write Buffer同样是为了保证数据完整性。

因为Redo Log一种操作日志,记录的是 " 在某个数据页上做了什么修改 ",用于MySQL异常崩溃恢复使用,本质上是物理日志。问题时如果数据页本身已经发生了损坏,Redo Log来恢复已经损坏的数据块就无效了,因为数据快已经是一个损坏的坏块。

而此时恢复数据需要的是一个跟原始数据块一样的页,而Double Write刚好存的就是数据块的副本,然后Redo Log再对数据块进行重做操作进行恢复。

可以这么说Double Write与Redo Log对于容灾场景,缺一不可。

总结

Double Write 部分页写入问题,崩溃恢复策略解决了每个阶段的Crash问题,结合Redo Log对崩溃数据能进行完成性恢复。

数据页落盘刷新的过程如下:

  1. Mysql的WAL日志预写日志,在数据页修改前先记录Redo Log
  2. Buffer Pool 数据页先copy到Double Write Buffer 的内存里
  3. Double Write Buffer 的内存数据刷到Double Write【磁盘中的共享表空间 ibdata】
  4. Double Write Buffer 的内存再刷到数据磁盘上【数据文件 ibd】

文末安利一波:

欢迎朋友们关注我的同名公众号📢📢:【小许code】,等你哦!🤣🤣
👨👩 朋友,希望本文对你有帮助~🌐

欢迎点赞 👍、收藏 💙、关注 💡 三连支持一下~🎈

🎈知道的越多,不知道的也越多,我是小许,下期见~🙇💻

相关推荐
希冀12315 分钟前
【操作系统】1.2操作系统的发展与分类
后端
GoppViper44 分钟前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文2 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people2 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
这孩子叫逆7 小时前
6. 什么是MySQL的事务?如何在Java中使用Connection接口管理事务?
数据库·mysql
罗政7 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
拾光师9 小时前
spring获取当前request
java·后端·spring
掘根9 小时前
【网络】高级IO——poll版本TCP服务器
网络·数据库·sql·网络协议·tcp/ip·mysql·网络安全
Java小白笔记10 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
Bear on Toilet10 小时前
初写MySQL四张表:(3/4)
数据库·mysql