redis之缓存穿透、缓存击穿、缓存雪崩及解决方案

缓存穿透

  指查询一个数据库中一定不存在的数据,那么缓存和数据库中都不存在。这种查询不存在数据的现象称为缓存穿透。

如根据商品编号查询详情;首先去查询缓存,缓存中自然没有然后去查询数据库,如果对这个key的请求量巨大,会直接穿透缓存直接查询数据库给数据库造成很大的压力,大量穿透请求严重情况下会造成数据库宕机。

  解决方案:

  1、缓存空值:对查询结果为空的情况也进行缓存,值设置为null,不过缓存时间设置短一些,如60s。如果对该key插入了数据到db之后要清理缓存

  2、使用布隆过滤器,将所有可能存在数据的key放在布隆过滤器中,查询缓存中没有数据之后,再使用布隆过滤器进行过滤请求,判断查询的key

    是否在布隆过滤器中,如果不在,则直接返回不再查询数据库。

  总结:

  1)针对空数据的key是有限的,重复率比较高的采用缓存空值的方式。

  2)针对大量请求key不存在、请求重复率低的数据,就没必要缓存,采用布隆过滤器直接过滤掉。

    

缓存击穿

  某个key是热点数据,扛着高并发请求集中对这个key进行访问,避免了访问数据库。那么在这个key失效的瞬间,持续的高并发就击穿了缓存直接

  请求数据库,对数据库造成很大压力。

  解决方案:

  1、热点key缓存永远不过期

    不设置过期时间

    将过期时间存在key的value中,程序判断将要过期时,异步线程对改key进行更新

  2、互斥锁,mutex lock 。当缓存失效的时候,线程不是立即去查询数据库,而是通过设置锁的方式占坑,如Redis的SETNX,判断返回值,谁拿

    到了锁谁去查询数据库然后设置缓存,没拿到锁的线程重试get方法。

缓存雪崩

  在某个时间段,发生大规模缓存失效的情况。

  有两种可能:

    1、缓存服务宕机 

    2:缓存中大量的key集中过期失效

  缓存服务宕机解决方案:

    1、宕机前:避免出现宕机,使用集群缓存,保证缓存服务的高可用

      可以使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况。

    2、宕机后: Hystrix限流&降级,避免MySQL宕机、尽快恢复缓存集群(重启自动从磁盘中加载数据恢复,需要提前开启Redis持久化机制)

  缓存集中失效解决方案:

  1、使用互斥锁

  2、数据预热,并设置不同的失效时间

    通过缓存reload机制,预先去设置或更新缓存,在即将大并发访问前手动在后台触发加载缓存不同的key,然后设置不同的过期时间,让缓存

    过期失效的时间点尽量均匀错开

  3、二级缓存

    两个缓存,a1为原始缓存,a2为备份缓存;a1短期,a2长期;a1过期了再去查询a2

  4、缓存永远不过期

互斥锁实现逻辑:

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //代表缓存值过期
          //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
          if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功
               value = db.get(key);
                      redis.set(key, value, expire_secs);
                      redis.del(key_mutex);
              } else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
                      sleep(50);
                      get(key);  //重试
              }
          } else {
              return value;     
          }
 }

END.

原文地址:https://www.cnblogs.com/yangyongjie/p/13802739.html