Redis

Redis 经典面试题: 缓存穿透、缓存击穿、缓存雪崩

2025-01-02  本文已影响0人  饱饱抓住了灵感

一、缓存穿透

1.1 概念理解

缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。
在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。

缓存穿透示意图.jpeg

缓存穿透问题可能会使后端存储负载加大,由于很多后端持久层不具备高并发性,甚至可能造成后端存储宕机。
通常可以在程序中统计总调用数、缓存层命中数、如果同一个Key的缓存命中率很低,可能就是出现了缓存穿透问题。

造成缓存穿透的基本原因有两个:

  1. 自身业务代码或者数据出现问题(例如:set 和 get 的key不一致),
  2. 一些恶意攻击、爬虫等造成大量空命中(爬取线上商城商品数据,超大循环递增商品的ID)

1.2 解决方案

1.2.1 缓存空对象

缓存空对象:是指在持久层没有命中的情况下,对key进行set (key,null)

缓存空对象会有两个问题:

第一,value为null 不代表不占用内存空间,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间,比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

1.2.2 布隆过滤器拦截

在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,当收到一个对key请求时先用布隆过滤器验证是key否存在,如果存在在进入缓存层、存储层。

可以使用bitmap做布隆过滤器。这种方法适用于数据命中不高、数据相对固定、实时性低的应用场景,代码维护较为复杂,但是缓存空间占用少。

布隆过滤器实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。

它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

布隆过滤器拦截的算法描述:

初始状态时,BloomFilter是一个长度为m的位数组,每一位都置为0。

添加元素x时,x使用k个hash函数得到k个hash值,对m取余,对应的bit位设置为1。

判断y是否属于这个集合,对y使用k个哈希函数得到k个哈希值,对m取余,所有对应的位置都是1,则认为y属于该集合(哈希冲突,可能存在误判),否则就认为y不属于该集合。可以通过增加哈希函数和增加二进制位数组的长度来降低错报率。

1.3 两种方案的对比

方案 适用场景 成本估量
缓存空对象 * 数据命中不高
* 数据相对固定实时性低
* 代码简单
* 需要更多的内存空间
* 数据不一致的处理
布隆过滤器 * 数据命中不高
* 数据相对固定
* 实时性低
* 代码相对复杂
* 需要较少的内存空间

二、缓存击穿

2.1 概念理解

系统中存在以下两个问题时需要引起注意:

在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。

2.2 解决方案

2.2.1 分布式互斥锁
只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可。此方案可以使用JetCache实现

缓存击穿互斥锁解决.jpeg

2. 永不过期
从缓存层面来看,确实没有设置过期时间,所以不会出现热点key过期后产生的问题,也就是“物理”不过期。 从功能层面来看,为每个value设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去更新缓

缓存击穿不过期解决.jpeg

2.3 两种方案对比

分布式互斥锁:这种方案思路比较简单,但是存在一定的隐患,如果在查询数据库 + 和 重建缓存(key失效后进行了大量的计算)时间过长,也可能会存在死锁和线程池阻塞的风险,高并发情景下吞吐量会大大降低!但是这种方法能够较好地降低后端存储负载,并在一致性上做得比较好。

永远不过期:这种方案由于没有设置真正的过期时间,实际上已经不存在热点key产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。

三、缓存雪崩

3.1 概念理解

如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

3.2 解决方案

PS: SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

上一篇 下一篇

猜你喜欢

热点阅读