Caffeine cache 学习01

   Caffeine是一款基于Java8开发的,高性能的,接近最优的本地缓存库

2.1 淘汰策略(Size-Based)

缓存命中率是衡量缓存系统优劣的重要指标,缓存通过保存最近使用或经常使用的数据于速度较快的介质中以提高数据的访问速度,缓存空间被填满后,会面临如何选择丢弃数据为新数据腾出空间的问题,因此选择合适的缓存淘汰算法会直接影响缓存的命中率。常用的缓存算法有:

  • First in first out (FIFO) 顾名思义,就是一个FIFO队列,先进入缓存的先被淘汰,忽略数据访问频率和次数信息。较为原始,命中率很低。

  • Least recently used (LRU) 最近最少被使用算法,其核心思想是【如果数据最近被访问过,那么将来被访问的概率也更大】,忽略了数据的访问次数,最常见的实现是维护一个链表,新数据插入到链表尾部,命中缓存的数据重新移至队尾,队列满后移出队首元素。LRU算法在有热点数据的情况下效率很好,但是如果面临突然流量或者周期性的数据访问是命中率会急剧下降。

  • Least frequently used (LFU) 最近最少频率使用,他的核心思想是【如果数据过去被多次访问,那么将来被访问的概率也更大】,LFU的实现需要为每个缓存数据维护一个引用计数,最后基于访问数量进行数据淘汰操作,因此实现较为复杂。LFU算法的效率通常高于LRU,能较好的介君突发流量或周期性访问问题,但是由于LFU需要一定时间累积自己的访问频率,因此无法应对数据访问方式的改变。

Caffeine的缓存淘汰是通过一种叫做W-TinyLFU的数据结构实现的,这是一种对LRU和LFU进行了组合优化的算法,下图给出了W-TinyLFU相对其他几种算法的表现,可以看出W-TinyLFU在数据查询、搜索、分析等场景均有优异的表现.

 

2.1.1 W-TinyLFU

Window TinyLFU主要由以下三个部分组成:

  • 准入窗口(Admission Window)也称伊甸区,是一个较小的LRU队列,其容量只有缓存大小的1%,这个窗口的作用主要是为了保护一些新进入缓存的数据,给他们一定的成长时间来积累自己的使用频率,避免被快速淘汰掉,同时这个窗口也可以过滤掉一些突发流量。

  • 频次过滤器(TinyLFU)是Caffeine数据淘汰策略的核心所在,他依赖CountMin Sketch非精确的记录数据的历史访问次数,从而决定主缓存区数据的淘汰策略,这个数据结构用很小的成本完成了缓存数据访问频次的记录和查找。

  • 主缓存区(Main region)用于存放大部分的缓存数据,数据结构为一个分段LRU队列(SLRU),包括ProtectedDeque和ProbationDeque两部分,其中ProtectedDeque的大小占总容量的80%,该部分使用TinyLFU的Adminsion策略进行数据的淘汰,一些访问频次很低的数据可以被快速淘汰掉,避免了主缓存区被新缓存污染。

2.1.2 CountMin Sketch

LFU算法实现的关键在于如何能高效的保存和读取数据最近的访问频次信息,通常的做法是使用popularity sketch(一种概率数据结构)来识别数据的"命中"事件,从而记录数据的访问次数。CountMin-Sketch便是其中的一种,他是通过一个计数矩阵和多个哈希算法实现的,如图所示:

 

CountMin Sketch的原理类似于布隆过滤器,也是一种概率型的数据结构。其中不同的row对应着不同的哈希算法,depth大小代表着哈希算法的数量,width则表示数据可哈希的范围。当记录某个指定key的访问次数时,分别使用不同的哈希算法在其对应的row上做哈希操作,如果命中了某一个数据格,则将该数据格的引用计数+1。当查询某个指定key的访问次数时,经过哈希定位到具体的多个数据格后,返回最小的数量计为该数据的访问次数。使用多个哈希算法可以降低哈希碰撞带来的数据不准确的概率,宽度上的增加可以提高key的哈希范围,减少碰撞的概率,因此我们可以通过调整矩阵的width和depth达到算法在空间、效率和哈希碰撞产生的错误率之间平衡的目的。Caffeine中的CountMin Sketch是通过四种哈希算法和一个long型数组实现的,具体的实现方法可以参考咖啡拿铁大神的文章——深入解密来自未来的缓存-Caffeine,这里就不再赘述了

淘汰过程

  1. 所有进入缓存区的数据会首先被add进Eden区,当该队列长度达到容量限制后,会触发Eden区的淘汰操作,超出的entries会被下放至主缓存区的Probation队列,这些数据被称为Candidate。

  2. 进入Probation队列的数据如果在没有被主缓存区淘汰之前获得了一次access,该节点会被add进Protected队列,这个过程称之为Node Promotion。

  3. Protecte队列如果达到其容量限制会触发Node Demotion过程,队列首部的元素会被peek出并下放到Probation队列。

  4. 主缓存区的大小(Probation的大小 + Protected的大小)达到了其容量限制会触发主缓存区的数据淘汰,Probation会被优先选择为淘汰队列,如果Probation为空,则选择Protected为淘汰队列。

  5. 分别选取淘汰队列的首部元素作为受害者(victim),尾部元素作为竞争者(candidate),通过对比两者的访问频次选择最终的淘汰者,其中访问频次通过CountMin Sketch获得。

这里Caffeine对于竞争者的淘汰并不只是简单的判断其访问频次小于或等于受害者,而是加入了以下逻辑:

  • 如果竞争者的访问频次大于5且小于或等于受害者频次,随机淘汰,这么做的原因主要是为了一定程度的避免哈希碰撞引起的受害者访问频次非自然增长,从而导致新数据无法被写入主缓存区。

  • 如果竞争者的访问频次小于等于5则直接淘汰竞争者,这是因为TinyLFU中记录数据的访问频次最大值为15,当超过这个最大值触发全局的reset后只有7,因此如果不加一个数据预热的过程,可能会导致一个频率较低的攻击者因为随机淘汰策略挤掉了热点数据。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值