mysql的doublewrite原理,double write(二次写)

本文深入解析MySQL中的Doublewrite机制,探讨其如何通过双重写入确保数据完整性,避免部分页写失败的问题。文章详细介绍了Doublewrite的工作原理、恢复流程及其对系统性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1 什么是double write

MySQL的数据页默认是16K,而文件系统的数据页是4K,IO操作是按页为单位就行读写的。这就可能出现数据库对一个16k的数据页修改后,操作系统开始进行写磁盘,但是在这个过程中数据库宕机导致没有完全将16K数据页写到磁盘上。数据库重启后,校验数据页,发现有数据页不完整,就起不来了(redo是基于完整数据页进行的恢复)。

为了解决这个问题,MySQL引入了double write这个特性。double write针对的是脏数据,提高innodb的可靠性,用来解决部分写失败(partial page write)。为了数据的持久性,脏数据需要刷新到磁盘上,而double write就产生在将脏数据刷盘的过程中。刷盘是一份脏数据写到共享表空间ibdata中,一份写到真正的数据文件永久的保存。写了两次脏数据,就叫double wriete。

1.2 double write原理

简单来说,double write就是将修改后的脏页先放到double write buffer区,这个区占用2M内存空间,buffer空间满或其他条件触发,使double write buffer存的脏页先写到共享表空间(在MySQL 8.0.20之前,doublewrite缓冲区存储区位于InnoDB系统表空间中。从MySQL 8.0.20开始,doublewrite缓冲区存储区位于doublewrite文件中),之后在写入数据文件。这个时候如果写了不完整的页,可以用共享表空间中完整的页加以覆盖,数据页完整了,数据库也就可以拉起了,之后的各种恢复就看redo log的了。redo log是按数据块的方式记录日志的,它是根据偏移量来记录修改。尽管数据被写入两次,但双写缓冲区不需要两倍的I / O开销或两倍的I / O操作。只需一次fsync()调用操作系统。数据就可以按较大的顺序块写入doublewrite缓冲区(除非 innodb_flush_method设置为 O_DIRECT_NO_FSYNC)。

8.0.20后,在默认情况下,为每个缓冲池实例创建两个双写文件:刷新列表双写文件和LRU列表双写文件。

刷新列表双写文件用于从缓冲池刷新列表中刷新的页面。刷新列表doublewrite文件的默认大小是InnoDB page size * doublewrite page bytes.。

LRU列表双写文件用于从缓冲池LRU列表中刷新的页面。它还包含用于单页刷新的插槽。LRU列表双写文件的默认大小为InnoDB page size * (doublewrite pages + (512 / the number of buffer pool instances)),其中512是为单页刷新保留的插槽总数。

至少有两个双写文件。双写文件的最大数量是缓冲池实例数量的两倍。

redolog写入的单位就是512字节,也就是磁盘IO的最小单位,所以无所谓数据损坏。

b612cf066065e0c395f3d0bb1a1b8c85.png

1.3 double write恢复流程

数据恢复有三种情况

脏数据写磁盘成功

刷盘成功,找检查点,进行前滚、回滚就行了。

共享表空间ibdata写失败

如果是写共享表空间失败,那么这些数据不会被写到数据文件,数据库会认为这次刷盘从没发生过,MySQL此时会从磁盘载入原始的数据,然后找检查点,redo log前滚、回滚就行了。

脏数据刷数据文件失败

写共享表空间成功,但是写数据文件失败,在恢复的时候,MySQL直接比较页面的checksum,如果不对的话,直接从共享表空间的double write中找到该页的一个最近的副本,将其复制到表空间文件,再应用redo log,就完成了恢复过程。因为有副本所以也不担心表空间中数据页是否损坏。

1.4 doublewrite的负载

double write是一个buffer, 但其实它是开在物理文件上的一个buffer, 其实也就是file, 所以它会导致系统有更多的fsync操作, 而硬盘的fsync性能是很慢的, 所以它会降低mysql的整体性能。

2、监控double write工作负载

mysql> show global status like '%dblwr%';

+----------------------------+-------+

| Variable_name | Value |

+----------------------------+-------+

| Innodb_dblwr_pages_written | 44 |

| Innodb_dblwr_writes | 8 |

+----------------------------+-------+

2 rows in set (0.00 sec)

关注点:Innodb_dblwr_pages_written / Innodb_dblwr_writes

开启doublewrite后,每次脏页刷新必须要先写doublewrite,而doublewrite存在于磁盘上的是两个连续的区,每个区由连续的页组成,一般情况下一个区最多有64个页,所以一次IO写入应该可以最多写64个页。

适合关闭double write

海量DML

不惧怕数据损坏和丢失

系统写负载成为主要负载

1.5 相关参数

mysql> show variables like '%double%';

+-------------------------------+-------+

| Variable_name | Value |

+-------------------------------+-------+

| innodb_doublewrite | ON |

| innodb_doublewrite_batch_size | 0 |

| innodb_doublewrite_dir | |

| innodb_doublewrite_files | 2 |

| innodb_doublewrite_pages | 8 |

+-------------------------------+-------+

5 rows in set (0.00 sec)

#innodb_doublewrite:是否开启doublewrite

#innodb_doublewrite_batch_size:定义要批量写入的双写页面数

#innodb_doublewrite_dir:定义双写缓冲区文件目录

#innodb_doublewrite_files:定义双写文件的数量

#innodb_doublewrite_pages:定义批量写入时每个线程的最大双写页数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值