2020年6月18日

Mysql Innodb 双写缓冲区(Doublewrite Buffer)

作者 codecafe

doublewrite buffer

Doublewrite解决了什么问题?

为了解决部分页面写入问题(Partial Page Write)。

MySQL写入修改时刷新整个页面(默认16kb),而不仅仅是刷新页面中已更改的记录。而系统的单次io,一般是512byte为单位的,在断电,OS crash(操作系统崩溃)情况下可能会丢失数据。

Doublewrite是指哪两次写入?

  1. 写Doublewrite buffer,注意: Doublewrite buffer是磁盘不是内存
  2. 写入数据文件。

写入顺序:先写doublewrite buffer,写成功后再写到数据文件。

Doublewrite buffer存储区位于什么地方?

innodb 什么时候将脏页写入Doublewrite buffer中?

由以下几个参数决定:

  • innodb_max_dirty_pages_pct_lwm:低位水平标记,达到该值将启动缓冲刷新,默认为10(百分比,脏页/缓冲池)
  • innodb_max_dirty_pages_pct: 脏页数量与缓冲池比例阈值,默认为90
  • 如果开启自适应刷新(Adaptive Flushing)InnoDB根据重做日志生成的速度和当前的刷新率,使用自适应刷新算法来动态调整刷新率。

如何查看双写缓冲区的大小?

8.0.20之前,Doublewrite buffer是系统表空间中连续的128个页(每个页16k),总共2M

$ innodb_space -f ibdata1 space-inodes-detail 

INODE fseg_id=7, pages=160, frag=32 pages (9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40), full=2 extents (64-127, 128-191), not_full=0 extents () (0/0 pages used), free=0 extents ()

双写缓冲区范围:从第64-191 page,分为两个block,每个64 page

8.0.20开始的doublewrite buffer由单独文件保存:

$ ls -lh /usr/local/mysql-8.0.20-macos10.15-x86_64/data/#ib_16384_*

-rw-r-----  1 _mysql  _mysql   192K  6 30 18:09 /usr/local/mysql-8.0.20-macos10.15-x86_64/data/#ib_16384_0.dblwr
-rw-r-----  1 _mysql  _mysql   8.2M  6 30 18:08 /usr/local/mysql-8.0.20-macos10.15-x86_64/data/#ib_16384_1.dblwr

Doubliewrite 文件格式
“` #_页面大小_文件编号.dblwr “`

Doublewrite buffer从脏页刷新速度由哪些参数控制?

清洗线程数由innodb_page_cleaners配置(8.0.20版本默认为4),单个线程最多每次写入doublewrite buffer 的页面数由innodb_doublewrite_pages变量控制, 在默认情况下为innodb_write_io_threads的值(默认4),
每秒写入次数还受到innodb_io_capacity (定义了每秒I / O操作数,默认值200)和innodb_io_capacity_max(InnoDB在由后台任务每秒执行的最大IOPS数 )控制。

如何查看doublewrite buffer 已写入情况?

mysql> show global status like '%dblwr%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Innodb_dblwr_pages_written | 103   |
| Innodb_dblwr_writes        | 30    |
+----------------------------+-------+
2 rows in set (0.05 sec)
  • Innodb_dblwr_pages_written 从mysql启动以来,已经写入doublewrite buffer 的页面数
  • Innodb_dblwr_writes 执行写入doublewrite buffer的次数(脏页刷新到doublewriete buffer的次数)

重启mysql,这两个变量会重置

如何通过doublewrite buffer恢复?恢复逻辑是什么样的?

  • 恢复时检查数据文件中页面的校验和是否与doublewrite缓冲区中页面的校验和不同,从而知道该页面是否已损坏.
  • 恢复时,innodb会在其原始位置检查doublewirte buffer的是否一致,如果不一致,则直接丢弃。
  • 如果是表空间不一致,则从双写缓冲区恢复。

double write一定需要吗?

生产环境建议开启。可以通过my.cnf中配置关闭:innodb_doublewrite=0或启动服务时加上参数关闭:--skip-innodb-doublewrite

为什么有了redo log,还需要doublewrite buffer?

redo log 是对数据页进行操作的,如果这个数据页已经损坏,则没法通过redo log来进行恢复

Double write对性能的影响

  • 通常情况下只会降低5%的性能。
    但是负载较大的情况下,特别是大量需要读取的数据不在buffer pool 缓冲区中,Doublewrite 的写入与随机读取之间竞争访问磁盘,性能降低30%以上都是可能的。
  • 如果Doublewrite buffer位于支持原子写入的Fusion-io设备上,则会自动禁用doublewrite缓冲区。

Doublewrite buffer在HDD和SSD磁盘写入有区别吗?

Doublewrite buffer 和redo log都是顺序写,如果启用了写入缓存,HDD更快(HDD擅长顺序写,SSD则不是)。

参考