Home

凡是过往 皆为序章

缓存穿透、雪崩、击穿

缓存穿透

请求的大量数据在缓存和数据库中都不存在,缓存永远不会生效,这些请求都会去访问数据库,导致数据库压力变大而卡死或者宕机。

发生场景

  • 数据原本存在,但由于某些原因被删除(误删除、主动清理),但前端或前置的应用程序依旧保有这些数据
  • 恶意攻击行为,利用不存在的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的过期时间