缓存替代策略
几个相关术语
- 缓存命中:当客户发起一个请求时,如果该请求的数据是在缓存中,这一数据就会被使用,这一行为叫做缓存命中
- 没有命中:cache miss就是没有命中,相对于缓存命中而言。如果缓存中还有存储空间,那么没有命中的对象会被存储到缓存中来。
- 存储成本:当缓存没有命中时,系统会从数据库或其他数据源取出数据,然后放入缓存。而把这个数据放入缓存所需要的时间和空间,就是存储成本。
- 缓存失效:当存储在缓存中的数据需要更新时,就意味着缓存中的这一数据失效了。
- 替代策略:当缓存没有命中时,并且缓存容量已经满了,就需要在缓存中去除一条旧数据,然后加入一条新数据,而到底应该去除哪些数据,就是由替代策略决定的。
替代策略的具体实现就是缓存算法,主流缓存算法有:
- Least-Recently-Used (LRU)
替换掉最近被请求最少的对象,这种传统策略在实际中应用最广。在CPU缓存淘汰和虚拟内存系统中效果很好。然而在直接应用与代理缓存中效果欠佳,因为web访问的时间局部性常常变化很大。
浏览器一般使用了LRU作为缓存算法。新的对象会被放在缓存的顶部,当缓存达到了容量极限,底部的对象被去除,方法就是把最新被访问的缓存对象放到缓存池的顶部。 - Least-Frenquently-Used (LFU)
替换掉访问次数最少的缓存,这一策略意图是保留最常用的、最流行的对象,替换掉很少使用的对象。然而,有的文档可能有很高的使用频率,但之后再也不会用到。传统的LFU的策略没有提供任何移除这类文档的机制,因此会导致“缓存污染”,即一个先前流行的缓存对象会在缓存中驻留很长时间,这样,就阻碍了新进来可能会流行的对象对它的替换。 - Least Recently Used 2 (LRU2)
是LRU-K的具体表现。LRU-K中的K代表最近使用的次数,因此LRU可以认为是LRU-1。LRU-K的主要目的是为了解决LRU算法“缓存污染”的问题,其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。
相比LRU,LRU-K需要多维护一个队列,用于记录所有数据被访问的历史。只有当数据的访问次数达到K次的时候,才将数据放入缓存。当需要淘汰数据时,LRU-K会淘汰第K次访问时间据当前时间最大的数据。
数据第一次被访问时,加入到历史访问列表,如果书籍在访问历史列表中没有达到K次访问,则按照一定的规则(FIFO,LRU)淘汰;当访问历史队列中的数据访问次数达到K次后,将数据索引从历史队列中删除,将数据移到缓存队列中,并缓存数据,缓存队列重新按照时间排序;缓存数据队列中被再次访问后,重新排序,需要淘汰数据时,淘汰缓存队列中排在末尾的数据,即“淘汰倒数K次访问离现在最久的数据”。
LRU-K具有LRU的优点,同时还能避免LRU的缺点,实际应用中LRU-2是综合最优的选择。由于LRU-K还需要记录那些被访问过、但还没有放入缓存的对象,因此内存消耗会比LRU要多。
此部分参考了优快云博主「圣小童」的原创文章《LRU算法四种实现方式介绍》 - Two Queues (2Q)
是LRU的另一个变种,把被访问的数据放到LRU的缓存中,如果这个对象再一次被访问,就把他转移到第二个、更大的LRU缓存,使用了多级缓存的方式。去除缓存对象是为了保持第一个缓存是第二个缓存池的1/3。这个算法也是分两段的,和LRU2的区别就是,前者第一段也是缓存,使用LRU算法,后者第一段只是一个记录访问次数的队列。 - SIZE
替换占用空间最大的对象,这一策略通过淘汰一个大对象而不是多个小对象来提高命中率。不过,可能有些进入缓存的小对象永远不会再被访问。SIZE策略没有提供淘汰这类对象的机制,也会导致“缓存污染”。 - LRU-Threshold
不缓存超过某一size的对象,其他与LRU相同。 - Log(Size)+LRU
替换size最大的对象,当size相同时,按LRU进行替换。 - Hyper-G
LFU的改进版,同时考虑上次访问时间和对象size。 - Pitkow/Recker
替换最近最少使用的对象,除非所有对象都是今天访问过的。如果是这样,则替换掉最大的对象。这一策略试图符合web网页的特定模式。这一策略也被建议在每天结束时运行,以释放被“旧的”、最近最少使用的对象占用的空间。 - Lowest-Latency-First
替换下载时间最少的文档。显然它的目标是最小化平均延迟。 - Hybrid
有一个目标是减少平均延迟。对缓存中的每一个文档都会计算一个保留效用,保留效用最低的对象会被替换掉。位于服务器s的文档f的效用函数定义如下:
( C s + K 1 / b s ) ∗ ( f r f ) K 2 s i z e f \frac{(C_s+K_1/b_s)*({fr}_f)^{K_2}}{{size}_f} sizef(Cs+K1/bs)∗(frf)K2
c s c_s cs是服务器s的连接时间; b s b_s bs是服务器s的带宽; f r f {fr}_f frf代表f的使用频率; s i z e f {size}_f sizef是文档f的大小,单位字节。 K 1 K_1 K1和 K 2 K_2 K2是常量, C s C_s Cs和 b s b_s bs是根据最近从服务器s获取文档的时间进行估计的。 - Lowest Relative Value (LRV)
LRV也是基于计算缓存中文档的保留效用,然后替换保留效用最低的文档。 - Adaptive Replacement Cache (ARC)
ARC介于LRU和LFU之间,为了提高效果,由2个LRU组成,第一个包含的条目是最近只被使用过一次的,而第二个LRU包含的是最近被使用过两次的条目,因此,得到了新的对象和常用的对象。ARC能够自我调节,并且是低负载的。 - Most Recently Used (MRU)
MRU与LRU是相对的,移除最近最多被使用的对象。当一次访问过来的使用,有些事情的是无法预测的,并且在缓存系统中找出最少最近使用的对象是一项时间复杂度非常高的运算,这时会考虑MRU,在数据库内存缓存中比较常见。 - First in First out (FIFO)
FIFO通过一个队列去跟踪所有的缓存对象,最近最常用的缓存对象放在后面,而更早的缓存对象放在前面,当缓存容量满时,排在前面的缓存对象会被踢走,然后把新的缓存对象加进去。 - Random Cache
随机缓存就是随意的替换缓存数据,比FIFO机制好,在某些情况下,甚至比LRU好,但是通常LRU都会比随机缓存更好些。
Markdown将文本转换为 HTML。
参考文献
- 《深入分布式缓存——从原理到实践》