[InnoDB 学习1-7] 两次写

 

两次写(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。

  1. 在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的double write buffer
  2. 之后通过double write buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。

    这个过程中,因为double write页是连续的,因此这个过程是顺序写的,开销并不是很大。

  3. 在完成double write页的写入后,再将double write buffer中的页写入各个表空间文件中,此时的写入则是离散的。
  4. 故障时若操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,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了。