前言
本文介绍 InnoDB 的刷脏控制策略,它是如何控制刷脏速率的,以及一些相关参数。
意义
了解 MySQL 的刷脏策略有什么意义?
当一条正确的 SQL 执行时偶尔延迟较高,无法复现场景时,可能就是 MySQL 刷脏导致的。通过了解 MySQL 的刷脏策略,可以帮助我们更好地使用 MySQL 及调优。
刷脏控制策略
innodb_io_capacity
innodb_io_capacity 变量告诉 MySQL 主机磁盘的 IO 性能,这样 InnoDB 就知道全力刷脏的时候,可以刷多快。
innodb_io_capacity_max 表示刷脏速度的最大值,默认是 200。
控制策略
InnoDB 知道了它刷脏的上限后,还需要确定它刷脏速度的控制策略,因为它不可能将所有 IO 都用于刷脏,还需要处理用户的查询请求。
控制策略关注两点,一是内存中脏页的占比,一是 redo log 的写入速率。
innodb_max_dirty_pages_pct 是脏页的占比上限,默认是 75%。InnoDB 会根据脏页的比例(假设为 M),计算出一个 0 ~ 100 的值,假设为 p1,计算逻辑如下:
F1(M)
{
if M>=innodb_max_dirty_pages_pct then
return 100;
return 100*M/innodb_max_dirty_pages_pct;
}
InnoDB 每次写 redo log 日志都会记录一个序号,当每新写入一条记录时,会计算当前这条日志的序号减去 checkpoint 记录序号的差值,InnoDB 再将这个差值应用于计算算法得到一个 0 ~ 100 的值,假设为 p2。该计算算法比较复杂,可以确定地逻辑是,当差值越大得到地结果越大。
取 p1 和 p2 之间的较大值 R,之后引擎的刷脏速率就是 R% * innodb_io_capacity。
邻居顺带刷脏策略
执行 SQL 时,刷脏会让语句执行变慢,而邻居顺带刷脏策略会让执行变得更慢。
当进行一次刷脏时,如果脏页的旁边的数据页也是脏页,那就会准备把这个邻居脏页也进行刷脏,并且将邻居刷脏的逻辑还可以蔓延,使得将相邻的脏页都刷脏。
该策略对于早期机械硬盘 IOPS 低是很有帮助的,可以减少很多随机 IO。但在当前 IOPS 较高的 SSD 磁盘下,这个策略显得鸡肋且有副作用。
所以,建议将该策略禁用,即设置 innodb_flush_neighbors = 0,MySQL8 默认是禁用该策略的。
参考
- [1] 为什么我的MySQL会“抖”一下