缓存穿透+解决方案

  • 缓存穿透(查询不存在的数据)

    • 查询不存在的缓存,由于缓存不命中,并且出于容错的考虑,就会进入存储层查询

    • 而如果从存储层查不到数据也不将这个不存在的数据写入缓存,

    • 风险:如果查询大量这种不存在数据查询请求,不命中缓存,也不写入缓存,一直请求存储层,DB很有可能会挂

  • 预防

    • 接口层增加校验,数据合理性校验
    • 缓存和数据库都没有的,可以将key-null写入缓存,设置短时间过期,防止被同一个key一直攻击
  • SpringCache解决方案

    • 空结果也缓存,默认不配置condition或者unless就行
 cache:   #使用的缓存类型    type: redis   #过期时间    redis:      time-to-live: 3600000      # 开启前缀,默以为true      use-key-prefix: true      # 键的前缀,默认就是缓存名cacheNames      key-prefix: XD_CACHE      # 是否缓存空结果,防止缓存穿透,默以为true      cache-null-values: true

缓存击穿+解决方案

  • 缓存击穿

    • 热点key失效时,这一刻,有大量该热点key请求未命中缓存,从数据库查找,导致数据库请求量暴增,压力增大
  • 预防

    • 设置热点key永不过期
    • 定时任务更新热点缓存
    • 设置互斥锁
  • SpringCache解决方案

    • 缓存的同步 sync
    • sync 可以指示底层将缓存锁住,使只有一个线程可以进入计算,而其他线程堵塞,直到返回结果更新到缓存中
@Cacheable(value = {"product"},key = "#root.args[0]", cacheManager = "customCacheManager", sync=true)

缓存雪崩+解决方案

  • 大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩

  • 预防

    • 存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
    • 设置热点数据永远不过期,定时任务定时更新
  • SpringCache解决方案

    • 设置差别的过时时间
    • 比如CacheManager配置多个过期时间维度
    • 配置文件 time-to-live 配置
    cache:#使用的缓存类型type: redis#过期时间redis:time-to-live: 3600000# 开启前缀,默以为trueuse-key-prefix: true# 键的前缀,默认就是缓存名cacheNameskey-prefix: XD_CACHE# 是否缓存空结果,防止缓存穿透,默以为truecache-null-values: true

热点key+解决方案

热点key存储不当的危害:缓存中的某些Key对应的value存储在集群中⼀台机器,使得所有流量涌向同⼀机器,成为系统的瓶颈,⽆法通过增加机器容量来解决

解决方案

  • 避免带宽或者传输影响,本地缓存热点key数据,对于每次读请求,将⾸先检查key 是否存在于本地缓存中,如果存在则直接返回,如果不存在再去访问分布式缓存的机器

  • 高可用集群,或主从哨兵模式,将热点key存储到本地缓存,且数据存储分配均匀