基本概念
-
什么是缓存污染
- 对于访问频次很少的缓存,不及时删除,浪费缓存空间
-
问题
- 污染的缓存占据大量空间,导致淘汰缓存
如何解决缓存污染问题
-
8种淘汰策略\
-
noeviction 不淘汰数据
-
volatile-random\
-
volatile-ttl\
-
volatile-lru 应用最广泛\
-
volatile-lfu\
-
allkeys-lru 应用最广泛\
-
allkeys-random\
-
allkeys-lfu\
-
\
volatile-random 和 allkeys-random
- 因为是随机挑选,不会根据访问情况来筛选数据,会导致缓存缺失,最终访问数据库
- 这两种策略在避免缓存污染上效果非常有限
volatile-ttl
- 主要针对设置了过期时间的数据,并不关心再次访问的情况,导致缓存缺失
- 创建时间早的数据,而不是最近访问的数据,除非明确知道下一次的访问时间
LRU
-
核心思想:如果一个数据刚刚访问过,这个数据为热数据,下次还会访问的
-
实现原理:
- 会在每个数据对应的 RedisObject 结构体中设置一个 lru 字段,用来记录数据的访问时间戳
- LRU 策略会在候选数据集中淘汰掉 lru 字段值最小的数据\
-
仍然会导致缓存污染
LFU
-
基本概念:会基于访问的时效性和访问频率进行淘汰
-
实现
-
在LRU的基础上增加计数器
-
优先淘汰访问次数最低的数据,访问次数相等则通过LRU进行淘汰
-
LRU
- 在RedisObject中增加lru字段(24位)
- 随机采样的方式
-
LRU
-
ldt 值:lru 字段的前 16bit,表示数据的访问时间戳
-
counter 值:lru 字段的后 8bit,表示数据的访问次数(最多记录255次)\
-
并不是每次访问都+1,对计数器进行优化,可以设置步长(1/step 才会+1)
-
一般可以将 lfu_log_factor 取值为 10
-
衰减
-
LFU 策略会计算当前时间和数据最近一次访问时间的差值,并把这个差值换算成以分钟为单位\
-
LFU 策略再把这个差值除以 lfu_decay_time 值,所得的结果就是数据 counter 要衰减的值\
-
如果业务应用中有短时高频访问的数据的话,建议把 lfu_decay_time 值设置为 1\
-
-
-
总结
-
缓存污染:留存的缓存,但实际上不会再次访问,但是会占据缓存空间
-
分析不同的淘汰策略是否有效解决缓存污染
-
noviction 不淘汰
-
volatile-random 和 allkeys-random 随机淘汰,不能解决缓存污染\
-
volatile-ttl 在明确过期时间可以使用\
-
LRU只考虑时效性,对于只访问一次的数据来说,LRU 策略无法很快将其筛选出来 使用场景更多
-
LFU(关注访问频次)在 LRU 策略基础上进行了优化,在筛选数据时,首先会筛选并淘汰访问次数少的数据,然后针对访问次数相同的数据,再筛选并淘汰访问时间最久远的数据
-
lru 字段,又进一步拆分成了 16bit 的 ldt 和 8bit 的 counter\
-
counter可以通过设置非线性的增长,避免达到255的上限\
-
-
-
优先使用 volatile-lfu 策略,并根据这些数据的访问时限设置它们的过期时间,以免它们留存在缓存中造成污染\
\