double write(二次写)
Posted _雪辉_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了double write(二次写)相关的知识,希望对你有一定的参考价值。
文章目录
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的最小单位,所以无所谓数据损坏。
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:定义批量写入时每个线程的最大双写页数
以上是关于double write(二次写)的主要内容,如果未能解决你的问题,请参考以下文章