基于冷热分离的LRU链表

MySQL中设计LRU链表,是将冷热数据分离,链表分为两部分,一部分是冷数据,一部分是热数据,冷热数据占比由配置项innodb_old_blocks_pct控制,默认为37,即37%是冷数据

在运行期间,数据页被加载到缓存页时,首先会被放在冷数据区域的链表头部

MySQL配置项innodb_old_blocks_time默认值1000(ms),即当你加载数据页到缓存页时,在1s后如果又访问了这个缓存页,那么它就会被移动到热数据链表的头部,因为此时MySQL认为你可能会经常访问该缓存页

基于冷热分离的LRU链表的设计思想很好的解决了MySQL预读机制带来的问题

MySQL预读机制会将数据页连带其附近的数据页都读入缓存页,导致LRU链表中原本被频繁访问的缓存页被移动到LRU链表的尾部并且被淘汰,这种设计是非常不合理的

但是基于冷热分离的LRU链表将LRU分为了两条链表,一条是热数据链表,存放那些经常被访问的缓存页,一条是冷数据链表,存放那些不被经常访问,有可能被淘汰的缓存页,所有的数据页读入到缓存页时首先会进入冷数据链表

热数据的移动

在热数据区域,如果一个缓存页被访问,不一定会立马移动到热数据链表的表头,因为频繁的移动链表也是有性能消耗的,因此,MySQL中设计为,如果热数据链表前25%的缓存页被访问,他们是不会被移动的,只有在后75%中的缓存页被访问,才会移动到表头,这样就能尽可能的减少链表中节点的移动,从而减小性能的损耗

什么时候将LRU链表中的冷热数据中的缓存页刷盘

定时刷盘,MySQL会起一个后台线程,运行定时任务,每隔一定的时间就将LRU链表的冷数据区域尾部的一些缓存页刷盘,然后清空这些缓存页,并放入free链表,从LRU链表删除,从Flush链表删除

什么时候把Flush链表中的缓存页刷盘

LRU刷盘只会将冷数据刷盘,但是热数据也是需要被刷盘的,因此MySQL后台线程也会在某个时间将flush链表中的缓存页都刷盘,然后这些缓存页被清空,从flush链表删除,从lru链表删除,放入free链表

空闲缓存页不足

如果Buffer Pool中的空闲缓存页不足,free链表都被使用了,lru链表中有一大堆的缓存页,flush链表中也有一堆缓存页,此时如果MySQL需要从磁盘文件中加载数据页到Buffer Pool,那么MySQL会从LRU链表的冷数据区域的尾部找到最不经常使用的缓存页,将其刷盘并清空,放入free链表,然后将数据页读入缓存页