文章目录
- 前言
- 什么是Doublewrite buffer
- 为什么要叫它Doublewrite呢,双写分别是哪两次写,体现在了什么地方呢
- 为什么需要Doublewrite buffer
- Doublewrite buffer的具体使用
- 1.假如还没有进行第一次写的时候crash了,也就是Doublewrite buffer和磁盘数据文件都没有写成功
- 2.假如第一次写成功,在往原有磁盘文件中写脏页的时候crash了,Doublewrite buffer拥有部分完整的数据
- 谈谈PgSQL和Oracle在这方面的处理
- 从操作系统再看Doublewrite Buffer
前言
来分享下我对MySQL innoDB引擎的特性之一:Doublewrite Buffer的理解。
我争取把想要表达的东西讲清楚~
捋之前先明确几个知识点
- MySQL InnoDB引擎默认IO的页大小为16k(可调整大小,但不推荐);操作系统的磁盘IO大小一般为4K或者1k,并不固定
- Doublewrite Buffer并不是内存开辟的一块区域,8.0.20之前是在系统表空间中,8.0.20之后是专门有了doublewrite files 。
什么是Doublewrite buffer
Doublewrite buffer并不是在内存中开辟的一块区域;
Doublewrite buffer并不是在内存中开辟的一块区域;
Doublewrite buffer并不是在内存中开辟的一块区域;
虽然它叫buffer结尾,但它确实是在磁盘中开启的空间!!!
8.0.20之前是存在于系统表空间中,8.0.20之后是专门有了doublewrite files存储;
对于5.7的文档,也是说明了Doublewrite buffer存在于系统表空间
体现形式至少是两个文件,如下图格式
#ib_16384_0.dblwr
#ib_16384_1.dblwr
MySQL 8.0文档很清晰的描述了Doublewrite buffer
是在磁盘上的一块连续的空间。
在学习Doublewrite buffer的过程中我翻阅了很多博客的文章,
发现很多博客将Doublewrite buffer描述地很不清晰,无法验证来源。
1.比如Doublewrite buffer是在内存中的一块空间
2.还有类似双写是先写内存,再写系统表空间
3.还有类似下图的架构,来自于鼎鼎大名的《MySQL技术内幕》但是官网版本也不可考证,如果有hxd知晓的,请指正
等等这些理论都不可考究,至少在官网的描述中,我并没有看到这些逻辑,如果大伙儿有明白的,滴滴我。
如下图,官方架构描述
为什么不直接写
可能会写坏原磁盘页数据
为什么要叫它Doublewrite呢,双写分别是哪两次写,体现在了什么地方呢
第一次 将脏页写Doublewrite buffer
第二次 在落盘Doublewrite buffer之后,再将脏页写入它们所在磁盘的位置
如下图所示在官方文档中,15.11.1 InnoDB Disk I/O 明确说明了 两次写的逻辑
为什么需要Doublewrite buffer
MySQL InnoDB引擎默认IO的页大小为16k;操作系统的磁盘IO大小一般为4K或者1k,并不固定;
那么当InnoDB将脏页flush到磁盘的时候,需要多次磁盘IO将数据写入。
将脏页直接刷入磁盘的过程中,在其中某次IO之后,假使意外发生,断电或者服务器异常,刷盘终止;对于InnoDB来说,后续重启读到的页数据是个不完整甚至是错误的数据页;上述问题就是所谓partial write。
重启InnoDB数据恢复是通过Redo Log来进行,应用 Redo Log有一个前提:数据页必须是完好无损的。要保证数据页的完整性,应用 Redo 日志之前需要修复损坏的数据页
综上所述8.0.20之后的doublewrite files就是在恢复过程中修复不完整的数据页。
Doublewrite buffer的具体使用
分情况讨论下,Doublewrite buffer两次写在crash之后的作用,如有不当之处,请指正~
本文具体暂不讨论redo log 和bin log的恢复过程
以下的前提redo log 是完整的文件
1.假如还没有进行第一次写的时候crash了,也就是Doublewrite buffer和磁盘数据文件都没有写成功
那么重启恢复的过程中,原有磁盘数据文件一定是完整的,但文件中并没有buffer pool中的脏页
读取redo log进行回放数据
校验原有磁盘数据文件页是完整的 通过
校验原有磁盘数据文件页的LSN 和 redo log文件的LSN
根据原有磁盘数据文件页的LSN,确定redo log恢复文件的起点
恢复文件
2.假如第一次写成功,在往原有磁盘文件中写脏页的时候crash了,Doublewrite buffer拥有部分完整的数据
那么重启恢复的过程中,使用Doublewrite buffer中的页数据进行覆盖写入脏页进入原有磁盘文件,假如Doublewrite buffer中的页数据不完整可以丢弃不用。
读取redo log进行回放数据
校验磁盘数据文件页是完整的 通过
校验磁盘数据文件页的LSN 和 redo log文件的LSN
根据磁盘数据文件页的LSN,确定redo log恢复文件的起点
恢复文件
谈谈PgSQL和Oracle在这方面的处理
以下是摘录自 https://blog.csdn.net/enmotech/article/details/105423975
PostgreSQL是通过full_page_write来解决这个问题,就是在数据页第一次发生变更的时候将整个页面记录到xlog日志中,这样出了问题就有了完整的数据页加xlog日志进行恢复,这样做的缺点是大大增加了xlog的日志量,也对性能有一定影响
Oracle 中不是没有partial write的问题,而是Oracle 本身具有很多数据块的完整校验机制,写失败就直接回滚掉了,甚至在Oracle 11gR2版本还有写数据文件发现IO异常直接crash 实例的特性(当然是为了更好的保护数据库的完整性)。总的来讲我个人认为Oracle的安全性还是非常高的。通过简单分析,也能说明为什么很多存储复制软件来做Oracle容灾,在关键时刻备库不一定能正常打开就的原因就是这样。
————————————————
版权声明:本文为CSDN博主「数据和云」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/enmotech/article/details/105423975
从操作系统再看Doublewrite Buffer
在有些操作系统和磁盘,Doublewirte Buffer可能并不需要开启。
原子写在这些系统上是支持的,每次IO的大小是大于MySQL的页大小;
也就不存在 partial write;
如果都使用了支持原子写的fusion-io 等存储设备,那么double write机制会被自动disable。
同时官方建议将innodb_fush_method设置为o_direct,这样可以充分发挥硬件性能。
除了硬件等支持,那么传统等文件系统比如ext4/xfs/zfs/VxFS 是否支持原子写呢?
实际上ext4/xfs对原子写支持目前都不是非常优化,zfs是天然支持的,很早的版本就支持了,另类的文件系统;
另外veritas的VxFS也是支持的,其官网有相关的解释。