缓存穿透、缓存击穿、缓存雪崩的原因及解决方案

一、缓存穿透

1 产生原因

客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会访问数据库。导致DB的压力瞬间变大而卡死或者宕机。

  • 大量的高并发的请求打在redis上
  • 这些请求发现redis上并没有需要请求的资源,redis命中率降低
  • 因此这些大量的高并发请求转向DB请求对应的资源
  • DB压力瞬间增大,直接将DB打垮,进而引发一系列“灾害”

缓存穿透发生的场景一般有两类:

  • 原来数据是存在的,但由于某些原因(误删除、主动清理等)在缓存和数据库层面被删除了,但前端或前置的应用程序依旧保有这些数据;
  • 恶意攻击行为,利用不存在的Key或者恶意尝试导致产生大量不存在的业务数据请求。

 2.解决方法

(1)缓存空对象

简单的来说,就是请求之后,发现数据不存在,就将null值打入Redis中。
 
优点:实现简单,维护方便
缺点:额外的内存消耗
      可能造成短期的不一致


思路分析:
        当我们客户端访问不存在的数据时,先请求 redis,但是此时 redis 中没有数据,
此时会访问到数据库,但是数据库中也没有数据,这个数据穿透了缓存,直击数据库,
我们都知道数据库能够承载的并发不如 redis 这么高,如果大量的请求同时过来访问这种不存在的数据,
这些请求就都会访问到数据库,简单的解决方案就是哪怕这个数据在数据库中也不存在,
我们也把这个数据存入到 redis 中去,这样,下次用户过来访问这个不存在的数据,
那么在 redis 中也能找到这个数据就不会进入到数据库了。

 (2)布隆过滤

     在客户端与Redis之间加了一个布隆过滤器,对请求进行过滤。 
 
     布隆过滤器的大致原理:布隆过滤器中存放二进制位。
               数据库的数据通过hash算法计算其hash值并存放到布隆过滤器中,
               之后判断数据是否存在的时候,就是判断该hash值是0还是1。
 
               但是这是一种概率上的统计,当其判断不存在的时候就一定是不存在;
                当其判断存在的时候就不一定存在。所以有一定的穿透风险

优点:内存占用较少,没有多余 key
缺点:实现复杂 存在误判可能 

综上所述qqt

               我们可以两种方案一起用,这样子最为保险。据统计使用布隆过滤器一般可以避免90%的无效请求。

二、缓存雪崩

1 产生原因

当redis中的大量key集体过期,可以理解为Redis中的大部分数据都清空 / 失效了,这时候如果有大量并发的请求来到,Redis就无法进行有效的响应(命中率急剧下降),也会导致DB先生的绝望。

缓存雪崩的场景通常有两个:

  • 大量热点key同时过期
  • 缓存服务故障或宕机

2 解决方法 

将失效时间分散开

常用且易于实现通过使用自动生成随机数使得key的过期时间TTL是随机的,防止集体过期。

给业务添加多级缓存

使用nginx缓存 + redis缓存 + 其他缓存,不同层使用不同的缓存,可靠性更强。

构建缓存高可用集群

主要针对缓存服务故障的情景,使用Redis集群来提高服务的可用性。

使用锁或者队列的方式

如果查不到就加上排它锁,其他请求只能进行等待,但这种方式可能影响并发量。

设置缓存标记

热点数据可以不考虑失效,后台异步更新缓存,适用于不严格要求缓存一致性的情景。

三、缓存击穿 

1.产生原因

 缓存击穿问题也叫热点Key问题,就是⼀个被高并发访问并且缓存重建业务较复杂的key突然失效了,
无数的请求访问会在瞬间给数据库带来巨大的冲击。

2 解决方法

使用互斥锁

只有一个请求可以获取到互斥锁,然后到DB中将数据查询并返回到Redis,之后所有请求就可以从Redis中得到响应。【缺点:所有线程的请求需要一同等待】

”提前“使用互斥锁 / 逻辑过期

在value内部设置一个比缓存(Redis)过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去。【缺点:不保证一致性,实现相较互斥锁更复杂】

提前对热点数据进行设置

类似于新闻、某博等软件都需要对热点数据进行预先设置在Redis中,或者适当延长Redis中的Key过期时间。

监控数据,适时调整

监控哪些数据是热门数据,实时的调整key的过期时长。

四、利用互斥锁解决缓存击穿问题

 核心思路:
         相较于原来从缓存中查询不到数据后直接查询数据库而言,现在的方案是 进行查询之后,
如果从缓存没有查询到数据,则进行互斥锁的获取,获取互斥锁后,判断是否获得到了锁,如果没有得到,
则休眠,过一会再进行尝试,直到获取到锁为止,才能进行查询
 
         如果获取到了锁的线程,再去进行查询,查询后将数据写入 redis,再释放锁,返回数据,
利用互斥锁就能保证只有一个线程去执行操作数据库的逻辑,防止缓存击穿。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值