一、什么是 "刷脏页"
在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 performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
mysql> select VARIABLE_VALUE into @b from performance_schema.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。