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

一、缓存功能

  当系统处于高并发时,为了防止数据库压力过大,引入缓存处理功能,流程如下:

    

 

 

   当引入缓存功能后,会引发出问题:(1)缓存穿透,(2)缓存击穿,(3)缓存雪崩。

二、缓存穿透

      

 

 

  解释:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

  注意:不能避免低频的缓存穿透,可以避免高频的缓存穿透。

  解决办法:

  1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null存入缓存中,缺点:当用户不断地以大量不同的key(缓存层和数据库)去访问时,缓存层就会存储大量的(key-null),所以会占用过多的内存,此时需要设置缓存有效期,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
  3. 在server端存储一个布隆过滤器,将mysql包含的key放如布隆过滤器中,布隆过滤器能过滤一定不存在的数据。

四、缓存雪崩

  解释:缓存层在同一时刻,大量缓存的数据同时失效,导致大量的请求跑到数据库。

  导致原因:

  (1)redis中缓存的数据有效期是一致的,然后失效也就是同一时刻。

    解决办法:给每一条数据加上一个随机有效期,不要突然同时失效。

  (2)redis数据库挂掉了

    解决办法:分布式缓存。

五、缓存击穿

  解释:缓存击穿是指当缓存中某个热点数据过期了,在该热点数据重新载入缓存之前,有大量的查询请求穿过缓存,直接查询数据库。这种情况会导致数据库压力瞬间骤增,造成大量请求阻塞,甚至直接挂掉。

        

缓存击穿解决方案:

(1)第一种是设置key永不过期;

(2)第二种是使用分布式锁,保证同一时刻只能有一个查询请求重新加载热点数据到缓存中,这样,其他的线程只需等待该线程运行完毕,即可重新从Redis中获取数据。

  第一种方式比较简单,在设置热点key的时候,不给key设置过期时间即可。不过还有另外一种方式也可以达到key不过期的目的,就是正常给key设置过期时间,不过在后台同时启一个定时任务去定时地更新这个缓存。

  第二种方式使用了加锁的方式,锁的对象就是key,这样,当大量查询同一个key的请求并发进来时,只能有一个请求获取到锁,然后获取到锁的线程查询数据库,然后将结果放入到缓存中,然后释放锁,此时,其他处于锁等待的请求即可继续执行,由于此时缓存中已经有了数据,所以直接从缓存中获取到数据返回,并不会查询数据库。

    

 

posted @ 2021-01-24 23:10  zwj鹿港小镇  阅读(123)  评论(0编辑  收藏  举报