缓存雪崩、缓存穿透和缓存击穿

发布于:2023-01-10 ⋅ 阅读:(388) ⋅ 点赞:(0)

个人原创:我的博客文章链接

一、缓存雪崩

什么是缓存雪崩呢?

缓存雪崩,是指同一时间段大量的缓存key同时到期(失效)或者Redis服务宕机,导致大量的请求(如果是大型电商平台如某宝、某东,甚至可以说是海量请求)瞬间到达数据库,这会给数据库带来巨大的压力。

下图是正常情况下,请求访问到Redis缓存,Redis收到请求并响应数据给客户端,只有部分在Redis中未做缓存的会到达数据库。

image

如果大量的缓存key过期,导致请求未命中Redis,大量的请求就会到达数据库,导致数据库压力剧增。

image

另外一种情况就更糟糕了,Redis宕机了。缓存key过期还只是部分请求,而不是全部的请求到达数据库,而Redis宕机的话,那就是所有的请求瞬间到达数据库。

image

解决方案:

针对以上两种情况,我们也有相对应的解决方案。

  • 给不同的缓存key的过期时间(TTL)添加随机值
    主要是防止在同一时段有大量的key同时失效

  • 利用Redis集群提高Redis服务的可用性,即高可用
    利用集群,哨兵机制,监控Redis主从的状态,如果发现主服务器宕机,马上选择一个从机作为新的主机,确保Redis能一直对外提供服务,另外主从还能实现数据的同步,确保数据的一致性,保证了Redis服务的高可用。

  • 给业务缓存添加降级限流策略
    在发生了重大的错误,短时间无法解决,我们就可以提前做好一个容错方案,比如说给服务降级,限制流量,甚至拒绝服务。虽然牺牲了一些服务,但是最终保护了数据库。

  • 给业务添加多级缓存
    比如浏览器缓存,对页面进行缓存,对JVM添加缓存等等,做一个多层级的缓存。

二、缓存穿透

什么是缓存穿透?

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存就永远不会生效,这些请求都会打到数据库。

image

请求的数据不存在,可能数据是瞎编的,也可能是记错了或者打错了,但是这些请求都会一直到达数据库。
如果这时一个很坏很怀的人,故意一直请求不存在的数据,很有可能就会搞垮我们的数据库。那我们该怎么办?

解决方案:

1.缓存空对象

请求的数据在数据库中也不存在时,数据库会把一个空的值缓存到Redis,这样下次请求不存在的数据时,就会直接命中Redis,不会到达数据库

优点:简单粗暴,方便

缺点:

  • 造成额外的Redis内存消耗
  • 还有可能造成短期的数据不一致

针对缺点,我们也可以有对应的实现来缓解。

可以在缓存空值时给其设置一个TTL,到期自动删除,缓解内存消耗

image

对于短期的数据不一致问题,我们可以给TTL设置的时间短一点,或者在数据库中的数据更新之后,立马缓存到Redis中

2.布隆过滤

在客户端和Redis之间加一层布隆过滤器,当客户端发送请求时,会先到布隆过滤器进行判断,如果请求的数据不存在,会直接拒绝;如果存在,再放行到Redis

image

布隆过滤器的实现原理可以看成是Map,存储的是二进制位,是数据库中的数据根据某一种哈希算法得到的哈希值,再将得到的哈希值返回二进制位。
个人理解,如果有偏差,欢迎指正!

优点:
内存占用较少,没有多余的key

缺点:

  • 实现复杂
  • 存在误判可能

如果布隆过滤器判断该请求的数据不存在,那就是不存在,直接拒绝;如果判断存在,也有可能是误判,请求依然会打到数据库,仍然会有小的穿透风险。

三、缓存击穿

什么是缓存击穿?

缓存击穿问题,也叫热点key问题。缓存雪崩是大量的key过期;而缓存击穿,则是部分key过期

过期的key是被高并发访问并且缓存重建业务较复杂的热点key。同样也是会导致无数的访问请求瞬间到达数据库带来巨大压力。

比如,常见的秒杀场景,缓存的秒杀就是热点key,在同一时段有大量用户在访问,并且秒杀的缓存重建起来也比较复制。如果该热点key失效,这些请求都会打到数据库,导致服务器不稳甚至崩溃。

image

解决方案:

互斥锁

优点:

  1. 没有额外的内存消耗
  2. 保证一致性
  3. 实现简单

缺点:

  1. 线程需要等待,性能受影响
  2. 可能会有死锁风险

image

逻辑过期

优点:线程不需要等待,性能较好

缺点:

  1. 无法保证一致性
  2. 有额外的内存消耗
  3. 实现复杂

image


网站公告

今日签到

点亮在社区的每一天
去签到