什么是缓存穿透、缓存雪崩和缓存击穿?你在项目中如何避免这些问题?

本题是一道高频题,在面试中会被经常问到,涉及到项目缓存的使用时,一般都会有缓存穿透,雪崩,击穿等问题,那该如何解决呢?

1. **缓存穿透 **

定义

缓存穿透是指查询的请求既不在缓存中,也不在数据库中。这种情况通常发生在用户查询的数据根本不存在或者用户请求的参数有问题。由于缓存系统不能找到对应的数据,查询请求会直接访问数据库,导致缓存失效,甚至可能频繁访问数据库,给后端数据库带来极大的压力。

避免策略

  • 空值缓存:当查询的数据不存在时,可以将“空值”缓存到缓存中(例如:设置一个特殊的标记,如 null 或特定的错误码),避免相同的无效请求频繁查询数据库。缓存过期时间设置较短,以避免空值长时间占用缓存。

示例:假设用户查询某个商品的库存,但该商品库存为 0,可以将该信息缓存,缓存时间可以设置为短时间,如 5 分钟。这样如果用户再次查询这个商品库存时,可以直接从缓存中读取,而不需要每次都访问数据库。

  • 参数校验:在请求到达缓存前,先进行参数校验,防止无效的查询(如参数为空、格式错误等)到达缓存层。
  • 布隆过滤器:使用布隆过滤器对查询的请求进行预处理。布隆过滤器可以判断某个数据是否存在,如果过滤器中没有,则直接返回,避免了无效请求访问数据库。

2. **缓存雪崩 **

定义

缓存雪崩指的是缓存中的数据在同一时刻失效,导致大量的请求同时访问数据库,从而引发数据库的高并发压力,可能导致数据库崩溃。通常这种情况发生在缓存中的大量数据设置了相同的过期时间,或者缓存清理时没有做好分布和隔离。

避免策略

  • 缓存过期时间随机化:为了避免所有缓存项在同一时刻过期,可以将缓存的过期时间设置为随机值或分散设置。比如设置缓存的过期时间为 10 分钟加上一个随机偏移量,这样就不会出现缓存全部在同一时刻失效的情况。
  • 加锁或队列处理:当缓存失效时,可以使用分布式锁或者队列来控制缓存的重建。具体做法是,当多个请求同时到达并发现缓存失效时,只有一个请求能通过加锁重新查询数据库并更新缓存,其他请求可以等待或直接从缓存中读取已经更新的内容。
  • 预加载缓存:对于一些热点数据,可以在缓存即将过期时进行提前加载,避免数据失效时出现高并发的请求直接访问数据库。这样可以通过定时任务或后台进程提前刷新缓存。

3. **缓存击穿 **

定义

缓存击穿是指查询的数据在缓存中失效,而恰好有一个请求同时访问该数据,导致缓存层失效并直接访问数据库。当缓存失效的数据正好是热点数据时,数据库会承受很大的压力,影响系统性能。

避免策略

  • 加锁机制:当缓存失效时,采用分布式锁机制来保证只有一个请求能够访问数据库并更新缓存。其他请求可以等待缓存更新,避免并发查询数据库。

例如,可以使用 Redis 的 SETNX(Set if Not Exists)命令来实现分布式锁,确保只有一个请求能够成功更新缓存。

  • 双重检查:在进行数据库查询之前,可以进行二次检查:首先检查缓存,如果缓存为空,再检查是否有其他请求正在更新该缓存。如果有其他请求在更新缓存,则等待,否则进行数据库查询并更新缓存。
  • 永不过期的缓存:对于一些热点数据,考虑将其设置为永不过期,或者设置较长的缓存时间,并定期进行维护更新。这种方式可以避免缓存频繁失效带来的压力。

本题小结:大家在项目中写了缓存相关的内容,要重视这三个问题,被考察的概率达到百分之90以上。

发表评论

后才能评论