当内存数据页跟磁盘数据页内容不一致的时候, 我们称这个内存页为**“脏页”。**
内存数据写入到磁盘后, 内存和磁盘上的数据页的内容就一致了, 称为**“干净页”。**
MySQL执行期间突然慢一下,且持续时间很短,可能在刷脏页,就是将内存中的数据保存在磁盘中。
什么时候会触发脏页?
- 1 innodb的redo log写满了,这时候系统会停止所有更新。把checkpoint 往前推进。
- 2 buffer pool内存不足,此时需要淘汰一些数据页,有可能会淘汰脏页,就要先把脏页刷到磁盘
刷脏页一定会写盘,就保证了每个数据页有两种状态:- 内存里的一定是正确数据。
- 内存里没有,磁盘上的一定是正确数据。
- 3 mysql认为系统空闲时,会刷盘。当然系统繁忙时,也会见缝插针刷盘。
- 4 mysql正常关闭。这时候, MySQL会把内存的脏页都flush到磁盘上
InnoDB刷脏页的控制策略
InnoDB的刷盘速度就是要参考这两个因素: 一个是脏页比例, 一个是redo log写盘速度。
告诉 InnoDB 所在主机的 IO 能力,正确地设置innodb_io_capacity 参数,使用fio工具统计:
fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
innodb_max_dirty_pages_pct是脏页比例上限,默认值是 75%。
平时要多关注脏页比例,不要让它经常接近 75%。
脏页比例是通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到:
select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
select @a/@b;
另外还有一个策略,当刷一个脏页时,该页的邻居页也是脏页,也会把边上的脏页一起刷掉。而且该逻辑会一直蔓延。
innodb_flush_neighbors 参数就是来控制该行为的,值为1会有上述机制,0则不会,只刷自己。
机械硬盘可能会有不错的效果,但ssd建议设置为0。
并且mysql 8.0 innodb_flush_neighbors 默认为0。