【大课堂】Redis 中的缓存雪崩、缓存穿透、缓存击穿

452 阅读5分钟

同学们好,Redis我们已经讲了一大半了,后面两节课,重点讲一些面试中常问的一些Redis问题,其中先来看一下缓存击穿、穿透、雪崩

缓存雪崩

简单一句话:不管是缓存失效、宕机等情况下,都会造成大量的请求直接落到数据库,导致CPU或者内存飙高,把数据库打挂了

一般缓存数据库数据的key: 表名:列名:主键名:主键值

当然这种情况就很多了,比如你给一堆秒杀商品统一设置的key,且有效期为10小时,10小时后正好抢购,哦吼~~~,大面积缓存失效,还有你缓存机器突然宕机了,哦吼~~~

所以根据上述情况做相应的方案。

  1. 采用Redis集群,提高高可用【宕机】
  2. 限流,避免同时处理大量请求,限流的方式有很多,这个我们后面会讲讲【宕机】
  3. key的过期时间采用随机值,避免同一时间大面积失效【失效】
  4. 设置多级缓存,两个缓存时间点不一样,但是也增加了复杂度【失效】
  5. 特殊值可以设置永不过期,只做更新缓存就好【失效】

引用github一文中的解决缓存雪崩的方案,针对事前、事中、事后分别给出了具体的解决方案,如下:

  • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
  • 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
  • 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。 上图中,我们增加ehcache本地缓存,相当于减轻Redis负担,先从本地缓存查询,限流组件可以设置请求次数,从而降低请求,Nginx好像也可以配置,一般是运维人员来做,其中没有通过的请求则直接走降级,比如返回默认值、友情提示是或者空值。这样的好处最起码保证系统不会挂掉,保证一部分可用,也算降级策略。

缓存穿透

简单一句话:大量Key不存在缓存中,也不存在与数据库中,如果出现大面积恶意请求,会把数据库打死

解决方案:缓存穿透最基本的解决方案就是参数校验,比如不合法的请求直接处理,或者查询数据库id不能小于0,电话或者邮箱格式要满足等等。以下是两个主要方案:

无效key缓存

比如缓存及数据库查询不到的key可以直接在Redis中缓存该key并设置过期时间,这种方式有一个缺点就是,如果无效key太多那么会导致Redis内存浪费太多,所以无效key一定要设置过期时间并且时间较短,比如一分钟较好。不是很建议用这种方案。

布隆过滤器

布隆过滤器原理

布隆过滤器(Bloom Filter)是一种数据结构,可以看做是由二进制向量(位数组)和一系列的随机哈希函数两部分组成的数据结构。

如何加入元素:

当一个元素加入到布隆过滤器中,首先会使用其中的哈希函数计算得出哈希值,多个哈希函数就得出多个哈希值,根据得出的哈希值作为位数组的下标并将值置位1.

如何判断元素是否存在:

对元素进行布隆过滤器中哈希函数求哈希值,根据哈希值判断对应数组下标值是否都为1,如果都为1才说明在布隆过滤其中

注意这个特性去重也很方便

布隆过滤器的优点:
  1. 利用位数组可以再海量数据中判断是否存在,由于每个元素只占1个bit,加入有100w的元素,也只占1000000Bit / 8 = 125000 Byte = 125000/1024 kb ≈ 122kb 的空间
  2. 这种数据结构也保证高效且性能很好
布隆过滤器的缺点:
  1. 错误识别率,布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在
  2. 删除难度高

布隆过滤器的代码实现建议大家下来看看Google开源的Guava中自带的布隆过滤器源码,Redis v4.0也提供了对应模块插件,也可以自行学习。

缓存击穿

简单一句话:缓存击穿类似于缓存雪崩,缓存雪崩是大面积的key失效,而击穿是某个key如果是热点key,当它失效那一瞬间就直接打到了数据库,量级太大数据库也扛不住

解决方案:

  1. 如果缓存的热点数据基本不更新可以设置为永久

  2. 如果更新不频繁且缓存更新时间较短,那么我们尽量让访问进入数据库的请求只有一条进入,因为进入的同时也要更新缓存,所以采用 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁来保障少量的请求从数据库获取数据并重建缓存,其余线程则等待锁释放后访问新缓存。下图是大体流程,代码大家可以自行实现。

  3. 如果更新频繁且更新时间较长,那么最好利用定时线程再失效前先重建缓存保证访问一直从缓存中获得。

总结

本节内容主要讲解了缓存雪崩、穿透、击穿三种情况,希望大家在学习的时候主要是多想想什么情况下会出现,不同情况下的解决方案是什么就可以了。好了,下课!