两次写(Double Write)
-------------------------------------
| 内存实例 |
| ------ copy -------------------- |
| |Page| ---> | | |
| ------ 1 | | |
| |doublewrite buffer| |
| ------ copy | | |
| |Page| ---> | | |
| ------ ------------------- |
| / \ |
-------------------------------------
/ \
write/ \ write
2 / \ 3
v v
-------------------------------- -----------------
| ------------- ------------- | | |
| |doublewrite| |doublewrite| | recovery | 数据库文件 |
| | (1MB) | | (1MB) | |--------->| (.ibd) |
| ------------- ------------- | 4 | |
| 共享表空间 | ------------------
--------------------------------
double write
由两部分组成:一部分是内存中的double write
,大小为2MB; 另一部分是物理磁盘上
的共享表空间中连续的128个页(即2个区extent),大小同样为2MB。
- 在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过
memcpy
函数将脏页先复制到内存中的double write buffer
。 - 之后通过
double write buffer
再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync
函数,同步磁盘,避免缓冲写带来的问题。这个过程中,因为double write页是
连续
的,因此这个过程是顺序写的,开销并不是很大。 - 在完成double write页的写入后,再将double write buffer中的页写入各个
表空间文件
中,此时的写入则是离散
的。 - (故障时)若操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从
共享表空间中double write
中找到该页的一个副本
,将其复制到表空间文件
,再应用重做日志。
mysql> show global status like 'innodb_dblwr%'; +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | Innodb_dblwr_pages_written | 6325194 | | Innodb_dblwr_writes | 100399 | +----------------------------+---------+
注:若2个写入页的比例远小于64:1,可说明系统写入压力并不是很高。
注:有些文件系统本身就提供了部分写失效的防范机制,如ZFS。此时就不需要启用double write了。