封面图
嗨~大家好啊,我是阿壮,一个后端程序员。Redis 现在成了缓存“专业户”,很多系统的缓存都在使用 Redis,Redis 中缓存雪崩、击穿、穿透也成了老生常谈的问题,今天带大家梳理一下,出现这些问题的原因和解决方案。
缓存雪崩
出现的原因
缓存雪崩出现的原因是当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到 DB 上,这样可能导致整个系统的崩溃。
解决方案
- 设置不同的过期时间
比较简单且好理解的方案是我们在缓存的过期时间上设置一个 1-5min 的随机值,这样每个缓存的过期时间重复率就会降低,就可以避免缓存在某一时刻大规模到期的情况。
- 针对热 key 设置永不过期
设置热 key 永不过期或者针对即将过期的热 key 使用异步线程不断的刷新过期时间。
- 限流,使用锁或者队列,避免同时刻大量请求打崩 DB
加锁或者队列的方式保证缓存的单线程写,这样可以避免缓存大量失效后,请求短时间内都打到 DB 上。缺点是系统的吞吐率降低。
- 分级缓存
缓存击穿
出现的原因
缓存击穿和缓存雪崩比较相似,缓存雪崩是 key 大部分失效,而缓存击穿式热点 key 失效。一个设置了过期时间的 key 在某个时间大并发直接请求,并且此时正好过期的情况下,请求在缓存中没有读取到数据就会直接打到 DB 上,导致服务崩溃。
解决方案
- 加锁更新
比如请求查询 A,发现缓存中没有,对 A 这个 key 加锁,同时去数据库查询数据,写入缓存,再返回给用户,这样后面的请求就可以从缓存中拿到数据了。
- 针对热 key 设置永不过期
- 限流,使用锁或者队列,避免同时刻大量请求打崩 DB
缓存穿透
出现的原因
根本原因是请求了缓存中不存在的 key,导致每次请求都打到 DB 上。通常处于系统容错考虑,我们会在查询后如果有结果则写入到缓存,这样下一次请求时就可以直接从缓存中读取数据。然后当请求的 id 在数据库中存在时,比如数据库中主键使用的自增 id,而请求的是-1,那么这将导致缓存中不存在这个数据而每次请求都会从数据库中查,这就失去了缓存的意义,当并发量很大时会导致系统宕机。
解决方案
- 虽然从 DB 中查到的空,但是仍然把数据写到缓存
这是最简单粗暴的方法,不管从 DB 中查到的是什么都会写入到缓存,缓存有效期设置短些即可,比如 <=5min。
- 使用布隆过滤器
布隆过滤器的原理是在你存入数据的时候,会通过散列函数将它映射为一个位数组中的 K 个点,同时把他们置为 1。当用户来查询 A,而 A 在布隆过滤器值为 0,直接返回,就不会打到 DB 了。使用布隆过滤器之后会有一个问题就是误判,因为它本身是一个数组,可能会有多个值落到同一个位置,那么理论上来说只要我们的数组长度够长,误判的概率就会越低。
- 做好参数校验
拦截非法的参数就可以减少 DB 中查不到数据的情况。
我是阿壮,一个后端程序员,微信搜一搜:科技猫,获取第一时间更新,我们下期见
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。