🗒️Day65【概念解析】InnoDB Doublewrite Buffer
00 分钟
2023-11-25
2023-11-27
type
status
date
slug
summary
tags
category
icon
password

整理定义

中文名称:双写缓冲区
英文名称:Doublewrite Buffer
MySQL 5.7版本
MySQL 5.7版本
MySQL 8.0版本
MySQL 8.0版本
双写缓冲区(Doublewrite Buffer)是一个存储区域,InnoDB 在将页面写入 InnoDB 数据文件中的正确位置之前先将页面写入从缓冲池刷新的位置。 如果在页面写入过程中存在操作系统、存储子系统或意外的 mysqld 进程退出,InnoDB 可以在崩溃恢复期间从双写缓冲区中找到页面的良好副本。
MySQL 8.0.20之前,双写缓冲存储区域位于InnoDB系统表空间中。 从MySQL 8.0.20开始,双写缓冲区存储区域位于双写缓冲文件(Doublewrite Buffer Files)中。

doublewrite buffer配置提供以下参数:

innodb_doublewrite

  • innodb_doublewrite参数控制是否启用doublewrite buffer。多数场景下默认是启用的。为了禁用doublewrite buffer,设置innodb_doublewrite=0或者启动MySQL服务时加-skip-innodb-doublewrite选项。例如在性能压测的场景下,如果您更关注性能而不是数据可靠性,您可以禁用doublewrite buffer。 如果doublewrite buffer位于支持原子写的Fusion-io设备上,则自动禁用doublewrite buffer,并使用Fusion-io原子写来执行数据文件写。但是,要注意innodb_doublewrite设置是全局的。当doublewrite buffer被禁用时,它对不在Fusion-io硬件上的数据文件也禁用。该功能仅在Fusion-io硬件上支持,在Linux中仅支持Fusion-io NVMFS。为了充分利用这个功能,建议将innodb_flush_method=O_DIRECT

innodb_doublewrite_dir

  • innodb_doublewrite_dir(8.0.20引入)定义了InnoDB创建双写文件的目录。如果目录没有指定,双写文件创建在innodb_data_home_dir目录下,没有指定默认在数据目录下。 哈希符'#'会自动创建在指定目录名前缀,避免与shema名冲突。然而,如果使用了'.', '#'. 或者'/'指定了目录前缀,则不在目录名前缀没有哈希符'#'。 理想情况下,双写目录应该放在最快的存储上。

innodb_doublewrite_files

  • innodb_doublewrite_files参数定义了双写文件的数量。默认情况下,每个缓冲池实例都会创建2个双写文件:一个刷新列表双写文件和一个LRU列表双写文件。 刷新列表双写文件用于从缓冲池刷新列表中刷新页。刷新列表双写文件默认大小是InnoDB page size * doublewrite page bytes. LRU列表双写文件是用于刷新从缓冲池LRU列表的页。它也包括单个页刷新的槽。LRU列表双写文件默认大小为InnoDB page size * (doublewrite pages + (512 / the number of buffer pool instances)),512是为单个页刷新保留的槽的总数。 至少有2个双写文件。双写文件的最大数量是缓冲池实例的两倍。(缓冲池实例的数量由参数innodb_buffer_pool_instances控制) 双写文件有以下格式:#ib_page_size_file_number.dblwr。例如,下面的双写文件是在一个InnoDB页大小为16KB,单个缓冲池的MySQL实例上创建: #ib_16384_0.dblwr #ib_16384_1.dblwr innodb_doublewrite_files参数用于高级性能调优。默认设定已经适用于大多数用户。

innodb_doublewrite_pages

  • innodb_doublewrite_pages参数(MySQL8.0.20引入)控制每个线程双写页的最大数量。如果这个值没有指定,innodb_doublewrite_pages设置为innodb_write_io_threads值。这个参数用于高级性能调优。默认值已经适用于大多数用户。

innodb_doublewrite_batch_size

  • innodb_doublewrite_batch_size参数(MySQL8.0.20引入)控制一批写入双写页的数量。这个参数用于高级性能调优。默认值已经适用于大多数用户。

复述展开

为什么需要双写缓冲区?

我们常见的服务器一般都是Linux操作系统,Linux文件系统页(OS Page)的大小默认是4KB。而MySQL的页(Page)大小默认是16KB。
可以使用如下命令查看MySQL的Page大小:
一般情况下,其余程序因为需要跟操作系统交互,它们的页(Page)都会大于等于操作系统的页大小,为整数倍。比如,Oracle的Page大小为8KB。
MySQL程序是跑在Linux操作系统上的,需要跟操作系统交互,所以MySQL中一页数据刷到磁盘,要写4个文件系统里的页。
notion image
需要注意的是,这个操作并非原子操作,比如操作系统写到第二个页的时候,Linux机器断电了,这时候就会出现问题了。造成”页数据损坏“。并且这种”页数据损坏“靠 redo日志是无法修复的
重做日志中记录的是对页的物理操作,而不是页面的全量记录,而如果发生partial page write(部分页写入)问题时,出现问题的是未修改过的数据,此时重做日志(Redo Log)无能为力。写doublewrite buffer成功了,这个问题就不用担心了
Doublewrite Buffer的出现就是为了解决上面的这种情况,虽然名字带了Buffer,但实际上Doublewrite Buffer是内存+磁盘的结构。
Doublewrite Buffer是一种特殊文件flush技术,带给InnoDB存储引擎的是数据页的可靠性。它的作用是,在把页写到数据文件之前,InnoDB先把它们写到一个叫doublewrite buffer(双写缓冲区)的共享表空间内,在写doublewrite buffer完成后,InnoDB才会把页写到数据文件的适当的位置。如果在写页的过程中发生意外崩溃,InnoDB在稍后的恢复过程中在doublewrite buffer中找到完好的page副本用于恢复。

理解体会

最后我们总结下双写缓冲器的一些关键点:

Doublewrite 解决了什么问题?

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

Doublewrite 是指哪两次写入?

  1. 写Doublewrite buffer,注意: Doublewrite buffer是磁盘不是内存
  1. 写入数据文件。
写入顺序:先写doublewrite buffer,写成功后再写到数据文件。

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

  • 在MySQL 8.0.20之前:位于InnoDB系统表空间中(ibdata文件)
  • 从MySQL 8.0.20开始:位于doublewrite文件中,文件由innodb_doublewrite_dirinnodb_doublewrite_files配置确定
doublewrite由两部分组成,一部分是内存中的doublewritebuffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewritebuffer,之后通过doublewritebuffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewritebuffer中的页写入各个表空间文件中,此时的写入则是离散的。
引用自:姜承尧. MySQL技术内幕:InnoDB存储引擎(第2版) (数据库技术丛书) (Chinese Edition) (p. 106). 机械工业出版社. Kindle 版本.

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

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

参考

📌
快速跳转链接
【概念解析】启动
【概念解析】Day 1 - 10
【概念解析】Day 11 - 20
【概念解析】Day 21 - 30
【概念解析】Day 31 - 40
【概念解析】Day 41 - 50
【概念解析】Day 51 - 60
【概念解析】Day 61 - 70
【概念解析】Day 71 - 80
【概念解析】Day 81 - 90
 
上一篇
Day66【概念解析】InnoDB Data Dictionary
下一篇
Day64【概念解析】InnoDB Undo Log

评论
Loading...