InnoDB 双写缓冲区

发布时间 2023-08-17 19:55:02作者: LARRY1024

Doublewrite Buffer

双写缓冲区(doublewrite buffer)是磁盘上的一块存储区域,双写缓冲存储区位于双写文件(doublewrite files)中,InnoDB 将页面冲刷(flush)到磁盘上的数据文件之前,会先将其写入缓冲池中的双写缓冲区。

如果在页面写入过程中,出现操作系统、存储子系统或 mysqld 进程意外退出,InnoDB 可以在崩溃恢复期间从双写缓冲区中找到这些页面的无损副本。

虽然数据被写入两次,但双写缓冲区不需要两倍的 I/O 开销或两倍的 I/O 操作。通过执行一次 fsync() 系统调用,就可以将一个大的连续块上的数据写入双写缓冲区。

注意,如果设置了 innodb_flush_method = O_DIRECT_NO_FSYNC 时,每次写操作之后,会跳过 fsync() 系统调用。

刷盘策略

innodb_flush_method 定义了数据刷新到数据文件和日志文件的策略,它会影响 I/O 吞吐量。

System Variable innodb_flush_method
Default Value (Unix) fsync
Default Value (Windows) unbuffered
Valid Values (Unix) fsync (或 0)
O_DSYNC (或 1)
littlesync (或 2)
nosync (或 3)
O_DIRECT (或 4)
O_DIRECT_NO_FSYNC
Valid Values (Windows) unbuffered (或 0)
normal (或 1)

Linux 上的刷新策略

Linux 上的刷新策略:

  • fsync: InnoDB 调用 fsync() 系统调用刷新数据和日志文件,fsync 是默认的刷盘策略。

  • O_DSYNC: InnoDB 使用 O_SYNC 标志打开和刷新日志文件,然后,调用 fsync() 将数据文件刷盘,InnoDB 不会直接使用 O_DSYNC,因为它在许多发型版本的 Unix 上都存在问题。

  • littlesync:该选项用于内部性能测试,目前不支持,存在使用风险。

  • nosync:该选项用于内部性能测试,目前不支持,存在使用风险。

  • O_DIRECT: InnoDB 使用 O_DIRECT (在 Solaris 上使用 directio())打开数据文件,然后调用 fsync() 将数据和日志文件刷盘。

    这个选项在某些 GNU/Linux 版本、FreeBSD 和 Solaris 上都可以使用。

  • O_DIRECT_NO_FSYNC:InnoDB 在刷新 I/O 期间使用 O_DIRECT ,但在每次写操作后,会跳过 fsync() 系统调用。

    • 在 MySQL 8.0.14 之前,此设置不适合 XFS 和 EXT4 等文件系统,这些系统需要系统 fsync()调用来同步文件系统元数据更改。

      如果我们不确定文件系统是否需要 fsync()系 统调用来同步文件系统元数据更改,最好改用 O_DIRECT。

    • 从 MySQL 8.0.14 开始,fsync() 在创建新文件、增加文件大小和关闭文件后调用,以确保同步文件系统元数据更改,每次写操作后仍然会跳过 fsync() 系统调用 。

    如果重做日志文件和数据文件驻留在不同的存储设备上,并且在数据文件写入从无电池支持的设备缓存中刷盘之前,发生意外退出,则可能会丢失数据。因此,如果我们使用或打算使用不同的存储设备来存储重做日志文件和数据文件,并且数据文件驻留在具有非电池支持的缓存的设备上,最好改用 O_DIRECT

在支持 fdatasync() 系统调用的平台上, MySQL 8.0.26 中引入的变量 innodb_use_fdatasync 允许 innodb_flush_method 使用 usefsync() 来替代使用 fdatasync()。除非后续数据检索需要,否则系统 fdatasync() 调用不会刷新对文件元数据的更改,从而提供潜在的性能优势。

Windows 上的刷新策略

Windows 系统的刷新包括 :

  • unbuffered 或 0: InnoDB 使用模拟异步 I/O 和非缓冲 I/O。

  • normal 或 1: InnoDB 使用模拟异步 I/O 和缓冲 I/O。

刷新策略总结

每个设置如何影响性能取决于硬件配置和工作负载,通常我们需要对特定的配置进行基准测试,这样才能决定使用哪个设置,或者是否保留默认设置。我们可以通过基准测试,观察状态变量 Innodb_data_fsyncs 查看每个设置的调用 fsync() 总数,

注意,如果启用了 innodb_use_fdatasync,则需要观察 fdatasync() 的调用次数。

另外,如果工作负载中存在同时读写的操作,可能会影响某个设置的执行方式,例如:

  • 在具有硬件 RAID 控制器和带电池的写入缓存的系统上,O_DIRECT 可以避免数据在 InnoDB 的缓冲池和操作的系统文件系统中缓存两次。

  • 在某些系统上,InnoDB 的数据和日志文件位于 SAN 上 ,对于主要是 SELECT 语句的读取密集型工作负载,默认的刷新策略 fsync 或者 O_DSYNC 可能会更快 。请始终使用反映您的生产环境的硬件和工作负载来测试此参数。

    存储区域网络 (Storage Area Network, SAN) 是一种基于块的存储,利用高速架构将服务器与其逻辑磁盘单元 (Logical Disk Unit, LUN) 相连。其中,LUN 是一系列通过共享存储池配置的块,以逻辑磁盘的形式呈现给服务器。服务器会对这些块进行分区和格式化,通常使用文件系统,以便可以像在本地磁盘存储上一样在 LUN 上存储数据。
    SAN 的设计可消除单点故障,因此具有极高的可用性和故障恢复能力,设计完善的 SAN 可以轻松承受多个组件或设备的故障。
    常见的 SAN 协议包括:光纤通道协议 (FCP)、IP 光纤通道 (FCIP) 、Internet 小型计算机系统接口 (iSCSI)、以太网光纤通道 (FCoE)、基于光纤通道的非易失性内存标准 (FC-NVMe)等。

双写缓冲区的配置

innodb_doublewrite

innodb_doublewrite 变量控制是否启用双写缓冲区,它是默认启用的。

要禁用双写缓冲区,可以设置 innodb_doublewrite 为 OFF。在更关心性能而不是数据完整性的场景,可以考虑禁用双写缓冲区。

innodb_doublewrite_dir

innodb_doublewrite_dir 变量定义 InnoDB 创建双写文件的目录 。

如果用户指定了目录,则 InnoDB 会在该目录中创建双写文件 innodb_data_home_dir,如果用户未指定,则双写文件的默认路径为数据目录。

理想情况下,双写目录应放置在最快的可用存储介质上

innodb_doublewrite_files

innodb_doublewrite_files 变量定义了双写文件的数量,默认值为:innodb_buffer_pool_instances \(\times 2\),即双写文件数量是缓冲池实例数的两倍,有效值为:\([2, 256]\)

由于,默认情况下,InnoDB 的缓冲池大小数为 128MB,缓冲池实例数为 1,因此,默认情况下,会有 2 个双写文件。

默认情况下,InnoDB 会为每个缓冲池实例创建两个双写文件:flush 链表双写文件(flush list doublewrite file)和 LRU 链表双写文件(LRU list doublewrite file)。

flush 链表双写文件

缓冲池中的 flush 链表中的页面会刷盘到 flush 链表双写文件,默认情况下,一个 flush 链表双写文件的默认大小 = InnoDB 页面大小 \(\times\) 双写页面的字节数。

LRU 链表双写文件

缓冲池中的 LRU 链表中的页面会刷盘到 LRU 链表双写文件,它还包含用于单页刷新的插槽。

默认情况下,一个 LRU 链表双写文件的大小 = InnoDB 页面大小 \(\times\) ( 双写页面数量 + ( 512 / 缓冲池实例数)),其中, 512 是为单页刷新保留的槽总数。

双写文件的最大数量是缓冲池实例数量的两倍,通常情况下,至少有两个双写文件,

Doublewrite 文件名具有以下格式:#ib_page_size_file_number.dblwr( 或者后缀 .dblwr 带有变量 DETECT_ONLY 的值)。

例如,InnoDB 页面大小为 16KB 的单个缓冲池的 MySQL 实例,创建的双写文件如下:

#ib_16384_0.dblwr
#ib_16384_1.dblwr

注意,innodb_doublewrite_files 变量一般用于高级性能调整,默认设置理论上适合大多数的用户。

innodb_doublewrite_pages

innodb_doublewrite_pages 变量控制每个线程的最大双写页数。

System Variable innodb_doublewrite_pages
Default Value innodb_write_io_threads
最小值 innodb_write_io_threads
最大值 512

如果未指定 innodb_doublewrite_pages 的值, 则该配置等于 innodb_write_io_threads 值。

注意,innodb_doublewrite_pages 变量一般用于高级性能调整,默认设置理论上适合大多数的用户。

innodb_doublewrite_batch_size

该 innodb_doublewrite_batch_size 变量控制批量写入的双写页数,默认为 0。

注意,innodb_doublewrite_batch_size 变量一般用于高级性能调整,默认设置理论上适合大多数的用户。