mysql的缓存页对LRU的改进;预读机制;及对应的调优

Posted 好大的月亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql的缓存页对LRU的改进;预读机制;及对应的调优相关的知识,希望对你有一定的参考价值。

概述

LUR(Least Recently Used):最近未使用。

传统的LRU就是维护了一个链表,链表的头部是最近使用的元素,尾部是最长时间没使用的元素。

mysqlbufferpool里有许多的缓存页,从磁盘中的读取的数据就存放在这些缓存页中供mysql操作,默认的缓存页大小是16Kb

改造的原因

mysql有时会有这样的操作场景,就是对某个大数据量的表进行全表扫描。那么此时会将buffer pool中的缓存页全部淘汰掉,存进这些全表扫描的数据。那么当下一波热点数据的请求进来的时候,就又需要从磁盘去读取数据到缓存页中,会导致IO开销增加。

所以MYSQLLRU进行了改造,分为冷/热两部分LRU链表。当新的数据要拉进缓存但是缓存页的数据满了的时候,就先开始淘汰冷链中的页数据。当冷链中的数据在1秒内被再次访问的时候,不会放到热链中去,只有在1秒之后被再次访问了,才会放到热链的头部去。

这个时间由innodb_old_blocks_time 控制,查询语句

show variables like 'innodb_old_blocks_time';

结构图如下所示

mysql的预读

什么是预读:当从磁盘上读取一个页的时候,把相邻的其他页也读进来。

这种机制带来的好处:可以节省磁盘io的时间,直接从内存中读取数据。

触发情况:

顺序访问了磁盘上一个区的多个数据页,当这个数量超过56(默认的阈值)的时候,innodb会触发预读机制。这个参数由innodb_read_ahead_threshold控制,查询语句

show variables like 'innodb_read_ahead_threshold';

对应的调优

MySQL 的数据最终是存储在磁盘上的,每次查询数据时,我们先需要把数据加载进缓存,然后读取,如果每次查询的数据都已经存在于缓存了,那么就不用去磁盘读取,避免了一次磁盘 IO,这是我们最期望的。因此为了尽量在 LRU 链表中缓存更多的缓存页,我们「可以根据服务器的配置,尽量调大 Buffer Pool 的大小。

可以通过如下命令去查看 Buffer Pool 的大小以及 Buffer Pool 实例的个数。

# buffer pool大小
show variables like 'innodb_buffer_pool_size';
# buffer pool实例个数
show variables like 'innodb_buffer_pool_instances';

缓存命中率、缓存页的空闲数、脏页数量、LRU 链表中缓存页个数、冷热数据的比例、磁盘 IO 读取的数据页数量等信息。可以通过如下命令查看:

show engine innodb status;

如果看到 youngs/s 这个值较高,说明数据从冷数据区移到热数据的频率较大,因此可以适当调大热数据所占的比例,也就是减小innodb_old_blocks_pct参数的值,也可以调大innodb_old_blocks_time参数的值

如果看到 non-youngs/s 这个值较高,说明数据被加载进缓存当中后,没有被移动到热数据区,这是因为在 1s 内被访问了,这很可能是全表扫描造成的,这个时候就可以去检查一下代码,是不是SQL语句写得不恰当。

以上是关于mysql的缓存页对LRU的改进;预读机制;及对应的调优的主要内容,如果未能解决你的问题,请参考以下文章

MySQL: 16 基于冷热数据分离方案优化后的LRU链表如何实现缓存页的淘汰机制

LRU 缓存机制及 3 种简单实现

Mysql中的LRU链表

MySQL: 17 MySQL是如何将LRU链表的使用性能优化到极致的?

LRU缓存机制的实现

MySQL: 18 优化后的LRU链表中尾部的缓存页淘汰刷入磁盘的机制