zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

【Redis入门笔记 09】缓存穿透、击穿与雪崩

Redis笔记缓存入门 09 穿透 雪崩 击穿
2023-09-11 14:20:00 时间

redis

☕前言:

Redis 数据库常常用来充当传统数据库的缓存。一个实际的场景是当用户的请求过来,先去查缓存中的数据,如果缓存中不存在,则再去查询数据库,如果数据在数据库中存在,则将数据放入缓存然后返回,如果数据库中也不存在,则直接返回失败。

redis

大部分情况下,加缓存是为了减轻数据库的压力,提升系统的性能。但是如果使用不好,它也会带来很多意想不到的问题,我们经常说的三个问题分别是缓存穿透、缓存击穿与缓存雪崩。


🍉缓存穿透

🏄‍♂️什么是缓存穿透?

如果有大量的查询请求,并且查询的 key 对应的数据在数据库中并不存在,每次针对此 key 的请求在缓存中获取不到,请求会转到数据库上,从而可能会导致数据库挂掉。

1

🏄‍♂️解决方案:

  1. 缓存空值: 如果一个查询返回的数据为空(不管是数据是否存在),我们仍然把这个空结果(null)进行缓存,并且设置一个较短的过期时间。
  2. 设置可访问的名单: 使用 BitMaps 类型定义一个可以访问的名单,名单 id 作为 BitMaps 的偏移量,每次访问和 BitMaps 里面的 id 进行比较,如果访问 id 不在 BitMaps 里面,进行拦截,不允许访问。
  3. 采用布隆过滤器: 布隆过滤器 (Bloom Filter)是由 Burton Howard Bloom 于 1970 年提出,它是一种 space efficient 的概率型数据结构,用于判断一个元素是否在集合中。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数),它的效率要远高于一般的算法,但是有一定的误识别率。当布隆过滤器说,某个数据存在时,这个数据可能不存在;当布隆过滤器说,某个数据不存在时,那么这个数据一定不存在。将所有可能存在的数据哈希到一个足够大的 bitmaps 中,一个一定不存在的数据会被这个 bitmaps 拦截掉,从而避免了对底层存储系统的查询压力。
  4. 进行实时监控: 当发现 redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。

🍓缓存击穿

🎯什么是缓存击穿?

key 对应的数据存在,但在 redis 中过期,并且恰好该数据还是 “热点” 访问数据,此时若有大量并发请求过来,这些请求会发现缓存失效从而直接从数据库中加载数据并写会缓存,这时候大量的并发请求可能瞬间把数据库服务压垮。

2

🎯解决方案:

  1. 预先设置热门数据: 对于很多热门 key,其实是可以不用设置过期时间,让其永久有效。比如最近的热点新闻,我们先让程序提前从数据库中查出数据并同步到缓存中,扛过高并发访问以后再把数据从 redis 中移除。
  2. 自动续期: 缓存击穿是由于 key 过期导致的,我们可以让程序在 key 快要过期之前,就自动给它续期。比如 key 的过期时间为 30 分钟,我们让程序每 20 分钟就查一次数据库同步缓存,自动重置过期时间为 30 分钟。
  3. 使用互斥锁: 某个线程查询缓存未命中,这时它会去获取互斥锁,然后查询数据库获取结果并将结果写入缓存中,最后释放锁。在该线程释放锁之前,其它线程都不能获取锁,只能睡眠一段时间后重试,如果能命中缓存,则返回数据,否则继续尝试获取互斥锁。这种方案并不推荐使用,使用锁会让性能受到影响,还可能会带来死锁的问题。

🍑缓存雪崩

⛄什么是缓存雪崩?

redis 中的 key 在某一时间集中过期,此时若有大量的并发请求过来,这些请求最终都会落在数据库上,从而导致后端的数据库服务挂掉。

3

缓存击穿与缓存雪崩的区别是击穿是一个 key 过期,雪崩是多个 key 过期。

⛄解决方案:

  1. 将缓存失效时间分散开: 我们可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
  2. 自动续期: 跟缓存击穿中的解决办法一样,在 key 快要过期的时候让另外的线程自动更新缓存。
  3. 构建多级缓存架构: 使用多个缓存服务,比如 nginx + redis + ehcache…
  4. 使用锁或队列: 用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。但不适用高并发情况。

🚀redis 系列专栏:Redis 快速入门
❤整理不易❤ 还请各位读者老爷们三连支持一下╰( ̄ω ̄o)

footer