27 | 缓存被污染了,该怎么办?

286 阅读3分钟

基本概念

  • 什么是缓存污染

    • 对于访问频次很少的缓存,不及时删除,浪费缓存空间
  • 问题

    • 污染的缓存占据大量空间,导致淘汰缓存

如何解决缓存污染问题

  • 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 策略,并根据这些数据的访问时限设置它们的过期时间,以免它们留存在缓存中造成污染\

  • zhuanlan.zhihu.com/p/102513831\

\