图解 LRU LFU ARC FIFO 缓存淘汰算法

6,788 阅读3分钟

FIFO 先进先出

First In First Out ,先进先出

FIFO按照“先进先出(First In,First Out)”的原理淘汰数据,正好符合队列的特性,数据结构上使用队列Queue来实现。

新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动,淘汰FIFO队列头部的数据;

优点:

实现简单

缺点:

无法根据数据的使用频次、时间等维度进行优化,会导致缓存命中率降低。

LRU 最近最少使用

Least Recently used 最近时间未使用,通常被翻译为「最近最少使用」

B 和 A 都在淘汰进程之前使用过,更新最新的使用时间。 C 则一直没有被使用,虽然不是最久的数据,但是根据 LRU,它需要被淘汰。

最近最少使用页面置换算法,也就是首先淘汰最长时间未被使用的页面。

关键是看页面最后一次被使用到发生调度的时间长短。

优点:

热点缓存将被持久命中

缺点:

当所有缓存数据都变成热点后,将失去 LRU 的优点。

LFU 最近最不常用

Least Frequently Used 最低频率使用淘汰算法,通常被翻译为「最近最不常用」

每当缓存被使用的时候( C B A),则将使用频率加 1,当进行淘汰进程的时候,将使用频率最低的数据淘汰( E )。

优点:

提高频繁使用的数据的命中效率

缺点:

当所有数据都很频繁访问的时候,将失去优点

单纯的 LFU 会有个问题会导致缓存失效,当最新加入的 E 在 F 进来之前,没有被访问过,那么它将被淘汰。还没有给 E 被访问的机会,E 就被淘汰了。所以我们可以在 E 进来的时候,设置一个中位数的访问频率,保证新数据不会被马上被淘汰。

ARC 自适应缓存替换

Adaptive Replacement Cache 自适应缓存替换算法,是一种适应性Cache算法, 它结合了LRU与LFU。

ARC 的精髓就是根据被淘汰数据的访问情况,而增加对应 LRU 还是 LFU 链表的大小。

ARC 包含了四个链表。 LRU 和 LRU Ghost , LFU 和 LFU Ghost, Ghost 链表为对应淘汰的数据记录链表,不记录数据,只记录 ID 等信息。

当数据 A 加入 LRU 后,如果 A 再次被访问,则同时被放到 LFU 链表中。所以 LFU 链表的缓存为 LRU 链表的多次访问的数据。

当 LRU 链表淘汰了 B,那么 B 的信息则进入到 LRU Ghost 链表。如果 B 在之后再次被访问,则增加 LRU 链表的大小,同时缩减 LFU 链表的大小。LFU 链表同理。

所以,这是一个根据最近未使用和最少频率使用动态调整的算法。

优点:

根据内存使用方式动态调整 LRU 和 LFU 的大小,以适应当前最佳的缓存命中。

缺点:

占用更多的内存空间

每一种算法都有自己的特色,但是真正用在程序中,或多或少都会进行对应的优化。比如 Redis 会同时使用 LRU 和 LFU ,同时 LFU为了体现时间维度特征而会主动将计数器减少等策略。