MySQL实战45讲 第十二讲笔记

脏页、干净页

当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据
写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。

flush

把内存更新到磁盘的过程叫做刷脏页(flush)。这个过程中并不涉及redo log擦除。redo log在重放的时候,如果一个页flush过,会跳过。

flush的时机

  1. redo log满了引发flush。
  2. 内存满了,淘汰了脏页引发flush。
  3. 空闲时间,更新磁盘数据。
  4. mysql正常关闭的时候。
    第三四种情况,不占用忙时,所以没什么影响。
    第一种情况,innodb一直在避免,因为一旦redo log满了,所有的更新都要被阻塞。
    第二种情况,innodb用缓冲池(buffer pool)来管理内存,缓冲池中的脏页一共有三种状态:
  • 还没有使用的
  • 使用了但是是干净页
  • 使用了且是脏页
    innodb的策略是尽量使用内存。刷脏页存在替换,淘汰页面中。
    以下两种情况是明显影响性能的。
  • 一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;
  • 日志写满,更新全部堵住,写性能跌为 0,这种情况对敏感业务来说,是不能接受的。

innodb刷脏页策略

innodb_io_capacity

innodb_io_capacity参数告知引擎磁盘的IO能力,控制脏页,推荐设置为磁盘的iops及全力刷脏页的速度。
fio工具可以测试磁盘随机读写的IOPS,

fio -filename=/dev/sdb1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest

脏页比例

参数 innodb_max_dirty_pages_pct 是脏页比例上限,默认值是 75%。
脏页比例是通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total 得到的,假设为M。

redo log写盘速度

InnoDB 每次写入的日志都有一个序号,当前写入的序号跟 checkpoint 对应的序号之间的差值,我们假设为 N。N一定程度上代表了日志写盘速度。

策略

根据上述算得的 F1(M) 和 F2(N) 两个值,取其中较大的值记为 R,之后引擎就可
以按照 innodb_io_capacity 定义的能力乘以 R% 来控制刷脏页的速度。
合理地设置 innodb_io_capacity 的值,并且平时要多关注
脏页比例,不要让它经常接近 75%。

有趣的策略

一旦一个查询请求需要在执行过程中先 flush 掉一个脏页时,这个查询就可能要比平时慢
了。而 MySQL 中的一个机制,可能让你的查询会更慢:在准备刷一个脏页的时候,如果
这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个
把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的
数据页也还是脏页的话,也会被放到一起刷。
在 InnoDB 中,innodb_flush_neighbors 参数就是用来控制这个行为的,值为 1 的时候
会有上述的“连坐”机制,值为 0 时表示不找邻居,自己刷自己的。
找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机 IO。机械硬盘的随
机 IOPS 一般只有几百,相同的逻辑操作减少随机 IO 就意味着系统性能的大幅度提升。
而如果使用的是 SSD 这类 IOPS 比较高的设备的话,我就建议你把
innodb_flush_neighbors 的值设置成 0。因为这时候 IOPS 往往不是瓶颈,而“只刷自
己”,就能更快地执行完必要的刷脏页操作,减少 SQL 语句响应时间。
在 MySQL 8.0 中,innodb_flush_neighbors 参数的默认值已经是 0 了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容