InnoDB中LRU算法

141 阅读3分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

Buffer Pool在使用过程中如果所有的缓存页都使用完毕,没有空闲的缓存页使用时,可以去LRU链表中的尾部找到一个最近最少使用的缓存页,把数据刷入磁盘中,腾出空闲页,然后加载所需要的磁盘数据页到内存中。 LRU本身的机制比较简单,只要刚从磁盘加载的数据放入缓存页后,就将这个缓存页放入LRU链表的头部,后面如果对其他缓存页有了访问就移动到头部,这样在LRU链表的尾部就一定是最近最少被访问的缓存页。

image.png

当在某些时候查询一批不常用的数据,这个时候就会把那些一直常用的缓存页刷入磁盘中,在这些不常用数据查询完成后,再次对常用数据查询的时候,这个时候就会从磁盘中读取数据然后写入缓存页中,这样的话,会造成IO的额外开销。

基于冷热数据分离设计LRU链表

MySQL在设计LRU链表的时候,采用的实际上是冷热数据分离的思想,将LRU链表拆分为两个部分:热数据和冷数据部分。冷热数据的比例由:innodb_old_blocks_pct参数控制,默认是37,冷数据占比37%。实际上的LRU链表如下图:

image.png

第一次加载数据(冷数据到热数据策略)

当第一次加载数据的时候,会被存放到缓存页冷数据区域的链表头部,并不是直接放到热数据区域。当第一次加载的缓存页就进行了一次访问的时候,是不是就立马把这个缓存页放到热数据区域的头部呢?这样的话,也是不合理的,如果刚加载了一个数据页到缓存页并且立马被访问就移到热数据区域的话,后面一直不在访问的时候,这样的逻辑就不是很合理。 MySQL设定了一种规则,通过innodb_old_blocks_time参数(默认值:1000毫秒)来避免这种情况发生,当数据页被加载到缓存页之后,在1s后还对这个缓存页进行了访问,这个缓存页才会被移动到热数据区域的链表头部去。

缓存不够用如何淘汰

基于LRU链表,当缓存页不够用的时候,这个时候就从LRU链表中的冷数据区域尾部的缓存页,刷入磁盘,腾出空闲页

LRU链表优化到极致(热数据频繁访问)

当对热数据进行访问的时候,如果每次访问了热数据中的缓存页都移动到头部的时候,这样频繁的移动对性能也不是太好。所以MySQL的LRU链表对热数据区域的规则进行了优化,只有缓存页在热数据区域的1/4后部分的缓存页被访问了,才会将缓存页移动到链表头部区。

基于上面的文件描述,可以结合下面的图来理解

image.png