当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”
刷脏页的时间
第一种是“redo log写满了,要flush脏页” 整个系统就不能再接受更新了,所有的更新都必须堵住。如果你从监控上看,这时候更新数会跌为0
第二种是“内存不够用了,要先将脏页写到磁盘” 这种情况是常态
InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
- 还没有使用的;
- 使用了并且是干净页;
- 使用了并且是脏页。
InnoDB的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少。
当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:如果要淘汰的是一个干净页,就直接释放出来复用;但如果是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用
一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;
第三种是MySQL空闲时
第四种是MySQL正常关闭
刷脏页的控制策略
innodb_io_capacity
它会告诉InnoDB你的磁盘能力 设置成磁盘的IOPS
innodb_max_dirty_pages_pct
脏页比例上限,默认值是75% 通过Innodb_buffer_pool_pages_dirty
/Innodb_buffer_pool_pages_total
得到的
InnoDB的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是redo log写盘速度
刷脏页的连坐”机制
一旦一个查询请求需要在执行过程中先flush掉一个脏页时,这个查询就可能要比平时慢了。而MySQL中的一个机制,可能让你的查询会更慢:在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷
innodb_flush_neighbors
值为1的时候会有上述的“连坐”机制,值为0时表示不找邻居,自己刷自己的
找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机IO。机械硬盘的随机IOPS一般只有几百,相同的逻辑操作减少随机IO就意味着系统性能的大幅度提升
使用的是SSD这类IOPS比较高的设备的话,建议把innodb_flush_neighbors的值设置成0
在MySQL 8.0中,innodb_flush_neighbors参数的默认值已经是0了