mysql的刷脏
脏页:内存数据页跟磁盘上数据页内容不一致,将内存页称为脏页
干净页:内存数据写入磁盘后,内存页跟磁盘页数据一致,称内存页为干净页
刷脏页的俩种情况:
1、redo log满了,这时候系统不能再接受更新了,所有的更新都必须堵住,这时候的更新数为0
2、内纯不够用了,要先将脏页写到磁盘。这种情况是常态
innodb用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
还有没使用的;innodb的策略是尽量使用内存,对于一个长时间运行的数据库来说,未被使用的内存页很少
使用了并且是干净页
使用了并且是脏页
3、数据库空余的时候
4、mysql正常关闭的时候
而当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:如果要淘汰的是一个干净页,就直接释放出来复用;但如果是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用。
所以,刷脏页虽然是常态,但是出现以下这两种情况,都是会明显影响性能的:
一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长 #查询会导致从redo log 将数据flush到磁盘上,然后返回查询结果
日志写满,需要flush到磁盘,这时候更新全部堵住,写性能跌为 0,这种情况对敏感业务来说,是不能接受的。
InnoDB 需要有控制脏页比例的机制,来尽量避免上面的这两种情况。
innodb_io_capacity #告诉innodb磁盘的IO性能为多少,一般设置为磁盘的IOPS
磁盘的 IOPS 可以通过 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_io_capacity 设置过小导致的问题:
数据库写入速度很慢,TPS很低,IO压力却很小,原因是innodb以为磁盘性能就那么小,刷脏比生产脏页还慢,脏页积累,影响查询更新性能
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 了。