40.如何避免缓存”雪崩”的问题?

? 缓存雪崩

缓存雪崩,是指缓存由于某些原因无法提供服务( 例如,缓存挂掉了 ),所有请求全部达到 DB 中,导致 DB 负荷大增,最终挂掉的情况。

? 如何解决

预防和解决缓存雪崩的问题,可以从以下多个方面进行共同着手

1)缓存高可用

通过搭建缓存的高可用,避免缓存挂掉导致无法提供服务的情况,从而降低出现缓存雪崩的情况。

假设我们使用 Redis 作为缓存,则可以使用 Redis Sentinel 或 Redis Cluster 实现高可用。

2)本地缓存

如果使用本地缓存时,即使分布式缓存挂了,也可以将 DB 查询到的结果缓存到本地,避免后续请求全部到达 DB 中。

当然,引入本地缓存也会有相应的问题,例如说:

  • 本地缓存的实时性怎么保证?
    • 方案一,可以引入消息队列。在数据更新时,发布数据更新的消息;而进程中有相应的消费者消费该消息,从而更新本地缓存。
    • 方案二,设置较短的过期时间,请求时从 DB 重新拉取。
    • 方案三,使用 「如果避免缓存”击穿”的问题?」 问题的【方案二】,手动过期。
  • 每个进程可能会本地缓存相同的数据,导致数据浪费?
    • 方案一,需要配置本地缓存的过期策略和缓存数量上限。

如果我们使用 JVM ,则可以使用 Ehcache、Guava Cache 实现本地缓存的功能。

3)请求 DB 限流

通过限制 DB 的每秒请求数,避免把 DB 也打挂了。这样至少能有两个好处:

  1. 可能有一部分用户,还可以使用,系统还没死透。
  2. 未来缓存服务恢复后,系统立即就已经恢复,无需再处理 DB 也挂掉的情况。

当然,被限流的请求,我们最好也要有相应的处理,走【服务降级】,提供一些默认的值,或者友情提示,甚至空白的值也行。

如果我们使用 Java ,则可以使用 Guava RateLimiter、Sentinel、Hystrix 实现限流的功能。

4)提前演练

在项目上线前,演练缓存宕掉后,应用以及后端的负载情况以及可能出现的问题,在此基础上做一些预案设定。


另外,推荐看下 《Redis架构之防雪崩设计:网站不宕机背后的兵法》 文章的 「二、缓存雪崩问题优化」 ,大神解释的更好,且提供相应的图和伪代码。