MySQL 刷脏页:原理、配置与监控

一、什么是 "刷脏页"

在MySQL使用InnoDB存储引擎时,数据首先被写入到内存中的缓冲池。这些数据页在某个时间点会被写入(或者说“刷新”)到硬盘上。已经在内存中修改但尚未写回磁盘的页面我们称之为“脏页”,而"刷脏页"就是将这些更改写回磁盘的过程。

二、InnoDB 刷脏页的控制策略

1、背景刷新(Background Flushing)

InnoDB 会在后台进程中持续进行数据页的刷新操作。当脏页的比例超过 innodb_max_dirty_pages_pct 参数设定的值时,背景刷新开始工作,直至脏页的比例下降到这个阈值以下。

2、即时刷新(Flush to Avoid Swapping)

当系统内存不足,或者需要空闲页来加载新的数据页时,InnoDB 会立即刷新一部分脏页。

3、同步刷新(Synchronous Flushing)

在某些情况下,如事务提交或者创建检查点(Checkpoint)时,InnoDB 会立即刷新脏页。

4、刷新列表刷新(Flush List Flushing)

当事务提交并生成了 redo log 后,相关的脏页会被添加到一个刷新列表中。InnoDB 会定期根据 redo log 的大小和其他因素刷新这个列表中的脏页。

5、自适应刷新(Adaptive Flushing)

InnoDB 根据当前 redo log 的写入速度、脏页的数量等多种因素,动态调整刷脏页的速度,以平衡脏页数量和避免检查点时产生大量 I/O 操作的需要。

三、innodb_io_capacity 配置参数的含义和作用

innodb_io_capacity 配置用于告诉 InnoDB 存储引擎进行 I/O 活动的能力。参数的值表示了系统每秒钟可以处理的 I/O 操作数(包括读和写)。默认值通常在较旧的硬件或虚拟化环境下设置为 200,在高性能 SSD 磁盘上则可能会设置得更高。

通过调整 innodb_io_capacity 的值,你可以根据你的硬件配置和工作负载来调整 InnoDB 的 I/O 行为。如果这个值设置得太低,InnoDB 可能无法充分利用你的硬件能力;如果设置得太高,可能导致 CPU 和磁盘 I/O 饱和,反而降低数据库性能。一般建议设置成磁盘的 IOPS。

四、如何通过 fio 工具来测试磁盘的IOPS?

下面的语句用来测试磁盘随机读写的命令:

fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest

以下是 fio 选项和参数的详细解释:

  • -filename=$filename:指定要进行 I/O 操作的文件或设备名。
  • -direct=1:设置直接 I/O 模式。当值为 1 时,会绕过操作系统的缓冲区,直接向硬件进行读写。这有助于获取底层存储设备的真实性能数据。
  • -iodepth 1:设置每个线程的 I/O 深度为 1。I/O 深度是指每个线程同时处理的 I/O 数量。
  • -thread:指定使用线程而非进程来创建工作负载。
  • -rw=randrw:设置 I/O 类型为随机读写。
  • -ioengine=psync:设置 I/O 引擎为 psync,即对每个 I/O 请求采取阻塞式 I/O。
  • -bs=16k:设置块大小为 16KB。
  • -size=500M:设置每个线程要读写的总数据量为 500MB。
  • -numjobs=10:设置并发线程(或进程)的数量为 10。
  • -runtime=10:限制测试的最长运行时间为 10 秒。
  • -group_reporting:对所有线程的性能数据进行汇总。
  • -name=mytest:给测试命名为 "mytest"。

总的来说,这个 fio 命令会产生 10 个独立线程,并且每个线程都将在指定的文件(或设备)上执行随机读写操作,每个线程读写的数据量总共为 500MB,每次读/写的数据块大小为 16KB,整个测试最多持续 10 秒钟。

五、innodb_max_dirty_pages_pct 配置参数的含义和作用

这个参数表示了 InnoDB 缓冲池中“脏”页面(即已修改但未写回磁盘的页面)占总页面的最大百分比。当脏页面的比例高于这个设定值时,InnoDB 就会启动后台刷新操作,将这些脏页面写回到磁盘上,以防止太多的脏页面导致数据库必须执行代价较高的即时刷新。默认值一般为75,意味着当脏页面超过缓冲池的75%时,就会触发后台刷新。

脏页比例是通过 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total 得到的,具体的命令参考下面的代码:

mysql> select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty'; 
mysql> select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
mysql> select @a/@b;

六、innodb_flush_neighbors 参数含义和作用

在 MySQL 数据库中,InnoDB 存储引擎使用了一种名为"邻居刷新"(Neighbor Page Flushing)的优化策略。当某个数据页被标记为脏页并需要刷入磁盘时,InnoDB 不仅会将这个脏页写回磁盘,还会检查并同时写回与它在磁盘上物理位置相邻的其他脏页。innodb_flush_neighbors 参数就是用来控制这种行为的。

1、参数详解

innodb_flush_neighbors 参数可以接受以下两个值:

  • 当其值设置为 1 时,开启“找邻居”机制,即进行邻居刷新;
  • 当其值设置为 0 时,关闭“找邻居”机制,每个脏页只负责自己的刷新。

2、适用场景

这个“找邻居”优化在机械硬盘时代是很有意义的,因为它可以通过将相关的 I/O 请求集中到一起,减少磁头的寻道时间,从而减少随机 I/O 操作。由于机械硬盘的随机 IOPS(输入/输出操作数)通常较低,因此降低随机 I/O 的数量通常意味着系统性能的显著提升。

如果你正在使用 SSD 或者其他 IOPS 较高的设备,建议将 innodb_flush_neighbors 的值设置为 0。

你可能感兴趣的:(mysql,数据库,mysql)