本地缓存—Caffeine Cache

文章目录缓存淘汰策略FIFO优点局限性LRU优点局限性LFU优点局限性W-TinyLFU维护频率CountMin Sketch支持随时间变化的访问模式-分段LRU(SLRU)hill climbing——爬山算法算法思路优点缺点Caffeine Cache使用缓存填充策略手动加载同步加载异步加载驱逐回收策略基于大小回收基于时间回收基于引用回收缓存淘汰策略FIFO先进先出(First in First out),在这种淘汰算法中,先进入缓存的会先被淘汰,会导致命中率很低,实现比较简单优点最简单、最公
摘要由CSDN通过智能技术生成

缓存淘汰策略

FIFO

先进先出(First in First out),在这种淘汰算法中,先进入缓存的会先被淘汰,会导致命中率很低,实现比较简单

优点

最简单、最公平的一种数据淘汰算法,逻辑简单清晰,易于实现

局限性

算法逻辑设计所实现的缓存的命中率是比较低的,因为没有任何额外逻辑能够尽可能的保证常用数据不被淘汰掉

LRU

最近最少使用 or 最近最不常使用 算法(Least Recently Used),每次访问数据都会将其放在队尾,如果需要淘汰数据,就只需要淘汰队首即可。

仍然有个问题,如果有个数据在 1 分钟访问了 1000次,再后 1 分钟没有访问这个数据,但是有其他的数据访问,就导致了这个热点数据被淘汰。

优点

LRU可以有效的对访问比较频繁的数据进行保护,也就是针对热点数据的命中率提高有明显的效果

局限性

LRU可以很好的应对突发流量的情况,因为他不需要累计数据频率。但LRU通过历史数据来预测未来是局限的,它会认为最后到来的数据是最可能被再次访问的,从而给与它最高的优先级,也就是置换出去了热点数据,把这些偶发性数据留下了,从而导致LRU的数据命中率急剧下降。

LFU

最近最少频率使用(Least Frequently Used),利用额外的空间记录每个数据的使用频率,然后选出频率最低进行淘汰。这样就避免了 LRU 不能处理时间段的问题

优点

LFU可以有效的保护缓存,相对场景来讲,比LRU有更好的缓存命中率。因为是以次数为基准,所以更加准确,自然能有效的保证和提高命中率

局限性

在 LFU 中只要数据访问模式随时间保持不变时,LFU能带来最佳的缓存命中率,但是对于淘汰历史突发流量的缓存就有点力不从心了。

比如有部新剧出来了,使用 LFU 给他缓存下来,这部新剧在这几天大概访问了几亿次,这个访问频率也在 LFU 中记录了几亿次。但是新剧总会过气的,比如一个月之后这个新剧的前几集其实已经过气了,但是他的访问量的确是太高了,其他的电视剧根本无法淘汰这个新剧,所以在这种模式下是有局限性。

也就是说:

  1. 需要给每个缓存项维护频率信息,每次访问都需要更新,这是个巨大的开销;
  2. 如果数据访问模式随时间有变,LFU的频率信息无法随之变化,因此早先频繁访问的记录可能会占据缓存,而后期访问较多的记录则无法被命中;

因此,大多数的缓存设计都是基于LRU或者其变种来进行的。相比之下,LRU并不需要维护昂贵的缓存记录元信息,同时也能够反应随时间变化的数据访问模式。然而,在许多负载之下,LRU依然需要更多的空间才能做到跟LFU一致的缓存命中率。因此,一个“现代”的缓存,应当能够综合两者的长处。

在现有算法的局限性下,会导致缓存数据的命中率或多或少的受损,而命中略又是缓存的重要指标

W-TinyLFU

前Google工程师发明的W-TinyLFU,是一种现代的缓存。Caffeine Cache就是使用这种缓存淘汰算法。如前所述,作为现代的缓存,W-TinyLFU需要解决两个挑战:

  1. 如何避免维护频率信息的高开销,给每个记录项维护频率信息,每次访问都需要更新,需要一个巨大的空间记录所有出现过的 key 和其对应的频次——低内存占用
  2. 如何反应随时间变化的访问模式,如果数据访问模式随时间有变,LFU 的频率信息无法随之变化,因此早先频繁访问的记录可能会占据缓存,而后期访问较多的记录则无法被命中——高命中率

维护频率

W-TinyLFU算法的基础——TinyLFU算法首先在存储数据的使用频率上用了CountMin Sketch算法。

CountMin Sketch

CountMin Sketch算法原理类似于布隆过滤器,能够得出元素出现的频率(不精确的频率)。

该算法由计数矩阵d[m][n]和多个哈希方法hash[m]实现,当给数据a增加频率时:

  1. 用m个哈希方法处理数据a,hash[i](a),能够得出m个哈希值h[i](其中1<=i<=m 且h[i] <= n);
  2. d[i][h[i]] = d[i][h[i]] +1(其中1<=i<=m);

发生一次读取时,矩阵中每行对应的计数器增加计数。

可以发现存在哈希冲突,因此,可能出现假正例,但是通过多个哈希方法及计数矩阵的方式,可以保证很低的False Positive Rate(假正率)。

统计数据a的频率:P(a) = min(d[i][hash[i](a)])(其中1<=i<=m)

估算频率时,取数据对应是所有行中计数的最小值(因为哈希冲突的存在,统计的频率不会比真实频率小)。这个方法从空间、效率、以及适配矩阵的长宽引起的哈希碰撞的错误率上做权衡。

截图

在 Caffeine Cache 中,维护了一个 4 bit CountMin Sketch用来记录 key 的使用频率。4 bit 也就意味着,统计的 key 最大使用频率为 15。

为了解决数据访问模式随时间变化的问题,也为了避免计数无限增长,TinyLFU 还采用了一种基于滑动窗口的时间衰减设计机制,借助于一种简易的 reset 操作:每次添加一条记录到 Sketch 的时候,都会给一个计数器上加 1,当计数器达到一个尺寸 W 的时候,把所有记录的 Sketch 数值都除以 2,该 reset 操作可以起到衰减的作用。可以证明,reset 操作带来的频率估计期望不变。


支持随时间变化的访问模式-分段LRU(SLRU)

在对同一对象的"稀疏突发"的场景下,TinyLFU 会出现问题。在这种情况下,新突发的 key 无法建立足够的频率以保留在缓存中,从而导致不断的 cache miss。

Window-TinyLFU(W-TinyLFU)通过两个缓存区域:主缓存窗口缓存 解决这个问题:

主缓存(main cache),使用 SLRU 逐出策略 和 TinyLRU 接纳策略,大小为总缓存的 99%;

窗口缓存(window cache),采用 LRU 逐出策略而没有任何接纳策略,大小为总缓存的 1%。

主缓存根据 SLRU 策略静态划分为 A1 和 A2 两个区域,80%的空间分配给热门项目(A2),并从 20%的非热门项目(A1)中挑选 victim(牺牲块,驱逐块)。所有请求的 key 都会被允许进入窗口缓存,而窗口缓存的 victim 则有机会被允许进入主缓存。如果被接受,则 W-TinyLFU 的 victim 是主缓存的 victim,否则是窗口缓存的 victim。

截图

同时窗口缓存和主空间的大小是根据工作负载特征动态确定的。如果偏向新近度,则倾向于使用大窗口,而偏向频率倾向使用较小的窗口。Caffeine Cache 使用 hill climbing 算法(爬山算法,一种局部择优方法)来采样命中率,进行调整并将其配置为最佳平衡。

W-TinyLFU 的目的是使该方案的行为像 TinyLFU 一样适用于 LFU 工作负载,同时仍然能够利用诸如突发之类的 LRU 模式。因为 99%的缓存分配给了主缓存(使用 TinyLFU),所以对 LFU 工作负载的性能影响可以忽略不计。另一方面,某些工作负载允许使用 LRU 友好模式。


hill climbing——爬山算法

爬山算法是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策,属于人工智能算法的一种。

算法思路
  1. 随机选择一个登山的起点;
  2. 每次拿相邻点与当前点进行比对,取两者中较优者,作为爬坡的下一步;
  3. 重复第2步,直至该点的邻近点中不再有比其大的点;
  4. 选择该点作为本次爬山的顶点,即为该算法获得的最优解。
优点

避免遍历,通过启发选择部分节点,从而达到提高效率的目的。

缺点
  1. 局部最大:某个节点比周围任何一个邻居都高,但是它却不是整个问题的最高点,局部最优解。
  2. 高地:也称为平顶,搜索一旦到达高地,就无法确定搜索最佳方向,会产生随机走动,使得搜索效率降低
  3. 山脊:搜索可能会在山脊的两面来回震荡前进步伐很小

解决方法:随机重启爬山算法


Caffeine Cache使用

maven依赖:

<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>2.9.0</version>
</dependency>

缓存填充策略

Caffeine Cache 提供了3种缓存填充策略:手动加载同步加载异步加载

手动加载

在每次 get key 的时候指定一个同步的函数,如果key不存在就调用这个函数生成一个值。

public static void main(String[] args) throws Exception {
   
    manulCache("姓名", "张三"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值