什么是缓存击穿、缓存穿透、缓存雪崩?

PS:这是多年黄历的老八股了,一定要理解清楚。

缓存击穿

缓存击穿指的是当一个具有高并发访问量的键(key)在某个时间点过期时,所有的请求直接访问数据库。

为了解决缓存击穿问题,可以采取以下策略:

  • 加锁更新:例如,当请求查询某个键A时,如果发现缓存中不存在该键,可以对键A进行加锁,并同时去数据库查询数据,然后将查询结果写入缓存,并返回给用户。这样后续的请求就可以从缓存中获取数据了。
  • 异步刷新过期时间:在值(value)中组合写入过期时间,并通过异步的方式不断刷新过期时间,防止缓存过期。
缓存穿透

缓存穿透指的是查询既不存在于缓存中,也不存在于数据库中的数据,导致每次请求直接访问数据库,就像缓存根本不存在一样。

缓存穿透会使得每次请求都需要查询存储层,失去了缓存保护后端存储的意义。它可能由以下两个原因导致:

  1. 自身业务代码问题。
  2. 恶意攻击,如爬虫造成的空命中。

针对缓存穿透问题,可以采取以下两种解决方案:

  • 缓存空值/默认值:在数据库未命中后,将一个空对象或默认值保存到缓存中。这样,再次访问这个数据时,就可以从缓存中获取,从而保护了数据库。

缓存空值存在两个问题:

    1. 存储更多的键:空值被缓存,意味着缓存层需要存储更多的键,占用更多的内存空间。如果是恶意攻击,则问题更加严重。对于这类数据,可以设置较短的过期时间,让其自动被清理。
    2. 数据不一致:缓存层和存储层的数据可能会在一段时间窗口内不一致。例如,设置过期时间为5分钟,如果此时存储层添加了这个数据,缓存层和存储层的数据就会不一致。可以利用消息队列或其他异步方式清理缓存中的空对象。
    • 布隆过滤器:在存储和缓存之前引入布隆过滤器,用于进行一层过滤,判断数据是否存在。如果数据判断为不存在,就不再访问存储层。
    缓存雪崩

    缓存雪崩指的是在某一时刻发生大规模的缓存失效情况,例如缓存服务宕机或大量键在同一时间过期。这会导致大量请求直接打到数据库上,可能导致整个系统崩溃。

    为了预防和处理缓存雪崩问题,可以采取以下策略:

    • 提高缓存可用性

      1. 集群部署:通过使用集群来提高缓存的可用性,可以使用Redis自身的Redis Cluster或第三方集群方案如Codis。
      2. 多级缓存:设置多级缓存,当第一级缓存失效时,访问第二级缓存,每个级别的缓存设置不同的失效时间。
    • 过期时间

      1. 均匀过期:为了避免大量缓存在同一时间过期,可以随机生成不同键的过期时间,避免过期时间集中在某一时刻。
      2. 热点数据永不过期。
    • 熔断降级

      1. 服务熔断:当缓存服务器宕机或响应超时时,为了防止整个系统出现雪崩,暂时停止业务服务访问缓存系统。
      2. 服务降级:在大量缓存失效、高并发和高负载的情况下,临时舍弃对一些非核心接口和数据的请求,直接返回预先准备好的 fallback(退路)错误处理信息。

    标签: java, Java面试题, Redis, Java问题合集, Java编程, Java问题精选, Java常见问题, Redis面试题