缓存穿透+解决方案
缓存穿透(查询不存在的数据)
查询不存在的缓存,由于缓存不命中,并且出于容错的考虑,就会进入存储层查询
而如果从存储层查不到数据也不将这个不存在的数据写入缓存,
风险:如果查询大量这种不存在数据查询请求,不命中缓存,也不写入缓存,一直请求存储层,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存储到本地缓存,且数据存储分配均匀