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为了体现时间维度特征而会主动将计数器减少等策略。