缓存穿透与缓存雪崩
分布式缓存系统存在的问题
- 一致性问题(难以彻底解决)
- 缓存穿透
- 缓存雪崩
- 缓存击穿
缓存穿透(查不到)
概念
查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方案:
- 空值缓存
- 布隆过滤器
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则 丢弃,从而避免了对底层存储系统的查询压力
空值缓存
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数 据将会从缓存中获取,保护了后端数据源
空值缓存存在的问题
- 由于 Redis 是单线程串行的,在设置 null key 之前的请求一定会穿透到数据库
- 因此可以提前加锁在 redis 上,使用
setnx
,设置成功等于获取成功,否则获取失败
存在问题:
- 缓存控制会消耗资源
- 即使设置了过期时间,还是会导致缓存层和存储层数据存在数据不一致的窗口期,对一致性造成影响
缓存击穿(量太大|缓存过期)
指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,造成数据库崩溃
这类数据往往是热点数据
解决方案
设置热点数据永不过期
互斥锁
分布式锁:使用分布式锁,保证对每个key同时只有一个线程去查询后端服务,其他线程没有获取分布式锁的权限,因此只需等待即可
这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
缓存雪崩(集中失效|宕机|停电)
缓存雪崩,是指在某一个时间段,缓存集中过期失效
缓存集中过期失效
有一堆缓存,它们的过期时间都一样,那么到了过期的时刻,它们就集体失效了,此时新的请求就会打到数据库上,如果这种请求量很大,就会体现为周期性的缓存失效,形成周期性的持久层数据库访问压力,也有可能导致数据库崩溃
缓存服务器宕机或停电
相当于缓存层直接没了,缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
redis高可用
搭建Redis集群,防止整个缓存层挂掉
限流降级
在缓存失效后,通过加锁或者队列来控制数据库写缓存的线程数量
数据预热
在正式部署前,先把可能被访问的数据访问一边,这样一来可能被大量访问的数据就被加载到了缓存中
在即将发生大规模并发访问前手动触发缓存中不同的key,设置不同的缓存过期时间,避免缓存集中失效