缓存淘汰算法

缓存淘汰策略的实现
从本质上来说,缓存算法并没有好坏之分,只有是否适用当前的业务场景。因此根据不同的业务场景设置不同的缓存算法会使缓存命中率更高。

一、FIFO

FIFO(First in First out)先进先出。可以理解为是一种类似队列的算法实现

实现概念:最先进来的数据,被认为在未来被访问的概率也是最低的,因此,当规定空间用尽且需要放入新数据的时候,会优先淘汰最早进来的数据。

优点:没什么优点

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

二、LRU

LRU(The Least Recently Used)最近最久未使用算法

实现概念:如果一个数据最近很少被访问到,那么被认为在未来被访问的概率也是最低的,当规定空间用尽且需要放入新数据的时候,会优先淘汰最久未被访问的数据。

优点:LRU很好的应对了针对于突发流量涌入的情况

缺点:对于周期性、偶发性的访问数据,有大概率可能造成缓存污染,置换出去了热点数据,把这些偶发性数据留下了,从而导致LRU的数据命中率急剧下降。

例如:当一个新剧热播,流量涌入,此剧的相关缓存登顶。但当新剧热度降低趋势变得平缓,其他周期性播出的综艺类节目涌入后将新剧缓存挤出, 这是我又访问新剧,则不得不又将新剧加入缓存,这显然不合时宜,因为新剧我已经访问过很多次了。

三、LFU

LFU(The Least Frequently Used)最近很少使用算法,与LRU的区别在于LRU是以时间衡量,LFU是以时间段内的次数

实现概念:如果一个数据在一定时间内被访问的次数很低,那么被认为在未来被访问的概率也是最低的,当规定空间用尽且需要放入新数据的时候,会优先淘汰时间段内访问次数最低的数据。

针对以上的实现概念可以看出,它相较于LRU其多出了访问次数的概念,可以理解为当有缓存命中时其对应该缓存的计数器会+1。

优点:LFU有效的保护了缓存,因为是以次数为基准所以更加准确,针对于访问概率差不多时,缓存命中率较高。

缺点:LFU需要额外的空间来存储计数器来记录访问频次。针对于一个数据的洪峰。后来又衰弱,由于其频率过高导致其缓存很难失效。

例如:当一个新剧热播,流量涌入,此剧的相关缓存登顶。但当新剧热度降低趋势变得平缓,但是由于其缓存命中次数过高,导致其缓存一直处于缓存队列中,一直不会失效,直到剩余所有缓存计数都超过了此缓存才将其排出。

四、W-TinyLFU

W-TinyLFU(Window Tiny Least Frequently Used)是对LFU的的优化和加强

实现概念:当一个数据进来的时候,会进行筛选比较,进入W-LRU窗口队列,以此应对流量突增,经过淘汰后进入过滤器,通过访问访问频率判决是否进入缓存。如果一个数据最近被访问的次数很低,那么被认为在未来被访问的概率也是最低的,当规定空间用尽的时候,会优先淘汰最近访问次数很低的数据

它也存储一个次数,但它为什么是对LFU的优化呢,因为其存储的值为Count-Min Sketch,Count-Min Sketch是一个hash操作,它扩增为多个hash,在多个hash地址上记录缓存命中次数。这样多个hash会导致原来hash冲突的概率降低,当查询数据时,且从当多个hash取得数据,取出多个hash数据中取其中的最小值,来定义为此缓存的命中次数。也就是Count Min的含义所在。

当某一个key的的计数器大于触发值(k),则整体计数器会除以2,这样解决了LFU的缓存难失效问题。

这样我就可以使用申请固定的空间大小来存储缓存计数,就算是hash冲突也没关系,因为从概率上来说我获取的最小值是最准确的。

其类似于布隆过滤器的实现,可以将布隆过滤器看成一种概率性数据结构,本质是高效的插入和查询。相比于传统的List、Map其更高效、占用空间更少。其实现是当有变量加入布隆过滤器时,通过K个映射函数将变量映射为位图中的K个点,将K个点的值由0置为1.当有新的元素加入时候继续映射,就算是点位重复也没关系,该点位依旧为1.当查询时,元素交于K个点。

1、若k个位置有一个为0,则该元素肯定不在集合中

2、若K个位置全部为1,则该元素有可能存在集合中

优点:在空间和时间维度上拥有巨大优势。

缺点:误差率的存在,应用较少,只有Caffine使用此算法。

你可能感兴趣的:(缓存)