缓存穿透
请求的大量数据在缓存和数据库中都不存在,缓存永远不会生效,这些请求都会去访问数据库,导致数据库压力变大而卡死或者宕机。
发生场景
- 数据原本存在,但由于某些原因被删除(误删除、主动清理),但前端或前置的应用程序依旧保有这些数据
- 恶意攻击行为,利用不存在的key或者恶意尝试导致产生大量不存在的业务数据请求
解决方案
- 对于无效访问直接拦截,比如 id 为负值的,不允许请求到达redis和数据库
- 对空值进行缓存
- 使用布隆过滤器
缓存雪崩
redis中的大量key集体过期,可以理解为redis中大部分数据情况、失效了,这时候有大量并发请求到来,redis就无法进行有效的响应。
发生场景
- 大量热点key同时过期
- 缓存服务故障或宕机
解决方案
- 将失效时间分散
- 常用且易于实现,通过自动生成随机数使得key的过期时间TTL是随机的,防止集体过期
- 添加多级缓存
- 使用nginx缓存 + redis缓存 + 其他缓存,不同层使用不同的缓存
- 构建缓存高可用集群
- 主要针对缓存服务故障的情景,使用redis集群来提高服务的可用性
- 使用锁或者队列的方式
- 如果查不到就加上排它锁,其他请求只能进行等待,但可能影响并发量
- 设置缓存标记
- 热点数据可以不考虑失效,后台异步更新缓存,使用与不严格要求缓存一致性的情景
缓存击穿
redis中的某个热点key过期,但是此时有大量的请求访问该过期的key
可以看成缓存雪崩的一个特殊子集
比如xxx塌房哩、xxx商品活动,这时候大量用户都在访问该热点事件,但是可能优于某种原因,redis的这个热点key过期了,那么这时候大量高并发对于该key的请求就得不到redis的响应,那么就会将请求直接打在DB服务器上,导致整个DB瘫痪。
解决方案
- 使用互斥锁
- 只有一个请求可以获取到互斥锁,然后查询数据库中的数据并返回到redis,之后所有的请求就可以从redis中得到响应。【缺点:所有线程的请求需要一同等待】
- 逻辑过期
- 在value内部设置一个比缓存过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去,【缺点:不保证一致性,实现更复杂】
- 提前对热点数据进行设置
- 类似于新闻、某博等软件都需要对热点数据进行预先设置到redis中,或者适当延长redis中key的过期时间