缓存池机制
InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:没使用过的,使用了但干净的,使用了的脏的。
当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。 内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”
InnoDB的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少。
当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。 这时候只能从最久不使用的数据页从内存中淘汰,如果是干净的 直接使用。如果是脏的则要刷到磁盘,变干净后才能用。
脏页刷新的机制
脏页刷新触发的场景:
- redo log写满了,要flush脏页
- 内存不够用了,要先将脏页写到磁盘
- mysql 空闲的时候
- mysql关闭的时候
脏页刷新隐藏的问题
刷脏页虽然是常态,但是出现以下这两种情况,都是会明显影响性能的:
- 一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;
- 日志写满,更新全部堵住,写性能跌为0,这种情况对敏感业务来说,是不能接受的。
InnoDB需要有控制脏页比例的机制,来尽量避免上面的这两种情况
脏页的控制策略
主要思路:
首先正确地告诉innoDB所在主机的IO能力,这样InnoDB才能知道需要全力刷脏页的时候。(可以通过磁盘iops工具得知—如fio) 对应的设置参数:innodb_io_capacity 默认为300
接下来,我们就一起看看InnoDB怎么控制引擎按照“全力”的百分比来刷脏页。
InnoDB的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是redo log写盘速度。对应参数innodb_max_dirty_pages_pct是脏页比例上限,默认值是75%。
脏页比例是通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的。
mysql> 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中,innodb_flush_neighbors 参数就是用来控制这个行为的,值为1的时候会有上述的“连坐”机制,值为0时表示不找邻居,自己刷自己的。
作用: 找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机IO。 SSD这类IOPS比较高的设备的话,我就建议你把innodb_flush_neighbors的值设置成0。IOPS往往不是瓶颈,而“只刷自己”,就能更快地执行完必要的刷脏页操作,减少SQL语句响应时间。