一次性说明白Redis的缓存穿透、缓存击穿和缓存雪崩

一、缓存穿透

1.1 什么是缓存穿透?

缓存穿透(Cache Penetration):指查询一个不存在的数据,由于缓存中没有数据,所以这个查询请求会直接穿过缓存层,到达数据库层,造成了数据库的压力。攻击者可以通过构造恶意请求,使得缓存层无法命中任何数据,从而导致请求直接访问数据库,从而引起数据库压力过大。如红色线条流程。

1.2 解决方案

(1)业务层校验

  用户发过来的请求,根据请求参数进行校验,对于明显错误的参数,直接拦截返回。

  比如,请求参数为主键自增id,那么对于请求小于0的id参数,明显不符合,可以直接返回错误请求。

(2)缓存空对象

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

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

(3)设置布隆过滤器

在客户端与Redis之间加了一个布隆过滤器,对请求进行过滤。 

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

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

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

二、缓存击穿

1.1 什么是缓存击穿?

缓存击穿:Redis中一个热点key在失效的同时,大量(多个线程)的请求过来,从而会全部到达数据库,压垮数据库。

假设此时该热点key的TTL时间到(失效了),则查询缓存未命中,会继续查询数据库,并进行缓存重建工作。但是由于查询SQL逻辑比较复杂、重建缓存的时间较久,并且该key又是热点key,短时间内有大量的线程对其进行访问,所以请求会直接 “打到” 数据库中,数据库就有可能崩掉!

1.2 缓存击穿解决方案(2种) 

(1)互斥锁

简单的来说:
          并不是所有的线程都有 “ 资格 ” 去访问数据库,只有持有锁的线程才可以对其进行操作。
不过该操作有一个很明显的问题,就是会出现相互等待的情况。

 

 (2)逻辑过期

不设置TTL
         之前所说导致缓存击穿的原因就是该key的TTL到期了,所以我们在这就不设置TTL了,
而是使用一个字段,例如:expire表示过期时间(逻辑上的)。当我们想让它 “ 过期 ” 的时候,
我们可以直接手动将其删除(热点key,即只是在一段时间内,其被访问的频次很高)。
 
这种方案巧妙在于,异步的构建缓存,缺点在于在构建完缓存之前,返回的都是脏数据。

 

 1.3.  互斥锁与逻辑过期的对比分析 

优点缺点
互斥锁

1、没有额外得内存开销

2、保证一致性

3、实现简单

1、线程需要等待,性能受影响

2、可能有死锁得风险

逻辑过期1、线程无需等待,性能较好

1、不保证一致性

2、有额外内存消耗

3、实现复杂

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

三、缓存雪崩

 

1.1  什么是缓存雪崩?

        缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

缓存击穿是部分key过期导致的严重后果,而缓存雪崩则是因为大量的key同时过期所导致的问题

 

1.2 缓存雪崩解决方案(4种) 

(1)给不同的Key的TTL添加随机值(推荐)
        操作简单,当我们在做缓存预热的时候,就有可能在同一时间批量插入大量的数据,
那么如果它们的TTL都一样的话就可能出现大量key同时过期的情况!!!
所以我们需要在设置过期时间TTL的时候,定义一个范围,追加该范围内的一个随机数。
 
(2)利用Redis集群提高服务的可用性
        使用集群提高可靠性
 
(3)给缓存业务添加降级限流策略
        微服务的知识
 
(4)给业务添加多级缓存  
        请求到达浏览器,nginx可以做缓存,未命中找Redis,再未命中找JVM,最后到数据库......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值