【Redis】缓存雪崩、缓存击穿、缓存穿透(原因 + 分析 + 解决方案)

1,553 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情 >>

缓存雪崩、缓存击穿、缓存穿透

相信很多使用过redis的朋友们都对redis中的缓存雪崩、击穿、穿透有一定的了解,那么今天就让我们一起来学习一下造成这三个问题的原因以及相应的解决方法。

一、缓存雪崩

为什么会导致缓存雪崩?

一般来说,redis在架构中充当缓存的角色,对于客户请求的数据,如果redis中有缓存且缓存未过期,则会直接由redis将数据返回,而不需要到达mysql数据库;只有在redis中没有缓存(或者缓存过期了),客户请求才会到达mysql。

整个过程如下图所示:

image.png

缓存雪崩的出现就是因为在同一时间内redis中有大量的key过期,或者redis宕机,而偏偏这时候恰好有大量的用户请求到来,此时的redis已经无法处理了,所以这些大量的请求都会到达mysql数据库。

image.png

因为大量的请求一时间到达,导致数据库压力骤增,严重的情况下可能导致数据库宕机,甚至引发一系列连锁问题。

以上所讨论的就是缓存雪崩的情况。

缓存雪崩的解决方案

情况一:大量key同一时间过期所致

在这种情况下,我们的一个很基本的想法就是避免大量的key的同一个时间点内过期,让key的过期时间尽可能均匀。

  1. 均匀地设置过期时间:redis中key的过期时间我们可以自己设置的
  2. 互斥锁:在一个用户请求发现redis无法处理的时候,加锁,保证同一时间内只有一个请求到达mysql,从而构建新的缓存,待缓存构建成功后,释放锁,则后续的请求就可以在redis中处理了
  3. 双key策略:主key设置过期时间,备key则不设置过期时间;主key过期了,此时请求来到则返回备key,并更新缓存,同时更新主、备key的数据
  4. 后台更新缓存:这种方案有两种实现: 其一、key不设置过期时间,但开启一个后台线程定期检查缓存是否有效;若失效,则立马更新缓存 其二、在一个用户请求到来发现缓存失效后,由消息队列发消息通知后台进程更新缓存。

情况二:redis宕机所致

这种情况一般是redis故障宕机所引起的缓存雪崩问题。

  1. 采用服务熔断或请求限流机制,暂停业务层访问,或者直接返回错误。请求限流是指限制可到达数据库的用户请求的个数,避免数据库压力骤增
  2. 构建redis缓存高可靠集群:假如主节点宕机后,会有从节点自动升级为主节点,不影响redis集群的可用性。

二、缓存击穿

缓存击穿是由于redis中热点数据过期,导致大量用户请求到达mysql数据库。

缓存雪崩包含大量key在同一时间内过期或者redis宕机两种情况,而缓存击穿是缓存雪崩第一种情况中的一个特殊情况;因为它强调的是热点的key过期。

其实直白点来说,缓存击穿可以看做是缓存雪崩的一个子集(缓存击穿是缓存雪崩情况的一部分)

也正因为这样,所以缓存击穿可以用缓存雪崩中的以下两种方案解决:

  1. 互斥锁
  2. 后台更新缓存

三、缓存穿透

缓存穿透是指用户所想访问的数据既不在redis中,也不在mysql数据库中,在这种情况下,一样会有大量的请求到达数据库中,导致数据库压力骤增(但是数据库中也没有相关数据的,无法正常返回的)

image.png

  1. 限制非法请求:防止大量恶意请求访问redis或者数据库中都不存在的数据
  2. 缓存默认值(空值):当发现出现缓存穿透的数据,可以在redis中给它设置默认缓存。
  3. 采用布隆过滤器快速判断数据是否存在