ARC缓存淘汰算法
LRU(Least Recently User) 最近最少使用算法,根据数据的历史访问记录来进行淘汰数据。缺点:对于全表扫的场景失效。
LFU(Least Frequently Used): 最近最不常用算法,根据数据的历史访问频率来淘汰数据。缺点:对于过期的访问频次高的不能马上淘汰掉。
ARC(Adaptive Replacement Cache): 自适应缓存替换算法,它结合了LRU与LFU,来获得可用缓存的最佳使用。
核心思想是:当时访问的数据趋向于访问最近的内容,会更多地命中LRU list,这样会增大LRU的空间; 当系统趋向于访问最频繁的内容,会更多地命中LFU list,这样会增加LFU的空间。
1. 整个Cache分成两部分,起始LRU和LFU各占一半,后续会动态适应调整partion的位置(记为p)除此,LRU和LFU各自有一个ghost list(因此,一共4个list)。
2. 在缓存中查找客户端需要访问的数据, 如果没有命中,表示缓存穿透,将需要访问的数据 从磁盘中取出,放到LRU链表的头部。
3. 如果命中,且LFU链表中没有,则将数据放入LFU链表的头部,所有LRU链表中的数据都必须至少被访问两次才会进入LFU链表。如果命中,且LFU链表中存在,则将数据重新放到LFU链表的头部。这么做,那些真正被频繁访问的页面将永远呆在缓存中,不经常访问的页面会向链表尾部移动,最终被淘汰出去。
4. 如果此时缓存满了,则从LRU链表中淘汰链表尾部的数据,将数据的key放入LRU链表对应的ghost list。然后再在链表头部加入新数据。如果ghost list中的元素满了,先按照先进先出的方式来淘汰ghost list中的一个元素,然后再加入新的元素。
5. 如果没有命中的数据key处于ghost list中,则表示是一次幽灵(phantom)命中,系统知道,这是一个刚刚淘汰的页面,而不是第一次读取或者说很久之前读取的一个页面。ARC用这个信息来调整它自己,以适应当前的I/O模式(workload)。
这个迹象说明我们的LRU缓存太小了。在这种情况下,LRU链表的长度将会被增加1,并将命中的数据key从ghost list中移除,放入LRU链表的头部。显然,LFU链表的长度将会被减少1。
同样,如果一次命中发生在LFU ghost 链表中,它会将LRU链表的长度减一,以此在LFU 链表中加一个可用空间。