Redis 缓存穿透、击穿、雪崩以及一致性问题

1,343 阅读3分钟

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

1. 缓存穿透

缓存穿透是指查询一个缓存和数据库不存在的数据。这种情况下,请求肯定会打到数据库,就可能导致数据库宕机。

解决这个问题有两种方法:

  • 缓存空查询,但是这样会占用额外的空间
  • 验证过滤,例如布隆过滤器

布隆过滤器

布隆过滤器是进行相对准确的存在性验证的高效且节省空间的做法,其底层原理是经过多层的哈希过滤。

简单的来说,我们维护一个哈希数组,对于所有存在的key值,会进行遍历,对每个key值都是用N个hash函数计算其会投射到的位置,这样我们仅能得到一个01数组的过滤器了。

当一个请求过来后,我们会使用N个hash函数分别计算请求的key会映射到数组的哪一位,只有每一位都全部通过,才允许请求通过。

image.png

经过上面的步骤,我们可以做到只要存在的key值一定能通过,但是不排除会有一小部分不存在的key通过过滤器的情况。

但是我们可以通过调整数组长度L以及hash函数的个数N来改变通过准确率的期望值,具体的数学推理过程大家感兴趣的可以再深入学习。

2. 缓存击穿

缓存击穿,是指缓存中没有但数据库中有的热点key在短时间被大量访问。

解决这个问题有三种方法:

  • 设置热点key不过期
  • 加分布式锁
  • 限流

3. 缓存雪崩

缓存雪崩是指在某一时间段缓存集中失效,导致请求全部走数据库,引起数据库压宕机。

解决这个问题,可以设置随机过期时间。

4. 缓存一致性问题

解决数据库与缓存不一致问题的主流做法是延迟双删

延迟双删的流程如下:

  1. 更新操作熟悉删除Redis缓存
  2. 之后更新数据库中的数据
  3. 更新操作休眠一段时间
  4. 更新操作再次删除Redis缓存

下面我们逐步来解析每一步操作的意义:

  1. 第一次删除Redis缓存:这是为了防止更新操作在更新MySQL数据库时,有读请求读到Redis中的脏数据。
  2. 再次删除Redis缓存:这是啥为了防止更新操作在第一次删除Redis缓存后,有读请求优先于更新请求到达MySQL,再次读取脏数据到Redis缓存。
  3. 休眠一段时间:这是为了防止更新操作在第一次删除Redis缓存后,有读请求优先于更新请求到达MySQL,但是晚于更新操作再次删除Redis缓存,导致Redis缓存被再次更新成脏数据。