引用:redis 击穿、穿透、雪崩产生原因及解决方案 - AmourLee - 博客园
https://www.cnblogs.com/dongl961230/p/15337415.html

 

一、前言

从架构的一个整体性来看,redis产生击穿、穿透、雪崩的情况的前提条件都是redis做缓存使用,并且产生了高并发,正常情况下我们利用关系型数据库(mysql、oracle等等)作为数据存储,如果并发量不大的情况完全可以hold住客户端的请求,如果高并发产生关系型数据库I/O就会成为瓶颈,这时会导致请求响应缓慢,严重会导致DB直接瘫痪。这时就要想尽一切办法阻止大量请求直接到达数据库,所以无论是Nginx限流、网关的限流、server层的降级处理、redis的缓存,唯一目的就是阻止大量请求直接到达DB。下面我们在这些理论的基础上讨论一下redis的击穿、穿透、雪崩。

二、redis的击穿

1、前提:redis肯定做缓存使用,并且key过期。【注意】这里是key失效,不是key不存在;

 2、分析:

redis只要做缓存使用一定会受到内存大小的限制,所以我们在使用redis做缓存时,无论是缓存key的过期时间到了还是redis内部的淘汰策略(LRU LFU) 都会有缓存失效的一瞬间,如果偏偏就是那么巧,在key失效的时大量的并发请求到达server ,然而此时缓存不存在,导致大量请求到达DB。这就是产生击穿的原因。

3、解决方案:

3.1、redis是一个单进程单实例的。所以并发请求都死排着队进入redis的,所以分为以下几个步骤:
  • 第一个请求进来发现没有key,立刻使用setNx(相当于一把锁);
  • 如果设置成功访问数据库,失败则睡眠一会再访问;
3.2、当然上面的方法会产生死锁的可能(如果第一个请求挂了),解决方法:
  • 设置锁的同时添加过期时间,如果超时自动释放锁资源;
  • 这里也存在一个问题那就是过期时间设置大小的问题,设置大了,如果第一个请求挂了,会导致后面的大量请求等待时间过长而超时,如果设置时间过短,自己没处理完别的请求进来了,这样循环下去,这也会存在一定的并发请求。
3.3、解决过期时间长短问题:
  • 可以开启一个守护线程来监控数据有没有从DB中获取出来放入缓存,如果没有完成则给锁续时间;
  • 可以使用已经封装好的 Redisson;
  • 同时也看到了redis实现分布式锁的复杂性,所以这里你也可以使用zookeeper来实现分布式锁;

三、redis穿透

1、前提:肯定发生了高并发,并且客户端请求的数据数据库不存在,更别期望缓存会存在。

 2、分析:

  • 举个例子你是一个卖家电的电商平台,别人就在你的客户端恶意并发请求母婴产品,这时就会导致大量的并发请求到达DB,造成数据库压力过大。

3、解决方案:

  • 使用布隆过滤器,这里你可以有几种集成的方案:1、直接放在客户端算法+bitmap;2、客户端只包含布隆算法,把bitmap放在redis中;3、redis集成布隆模块;

 

  •  当然布隆过滤器存在一个问题,就是只能添加不能删除,如果你可以容忍这个问题,ok 直接使用没问题,如果不能容忍,可以使用布谷鸟等其他过滤器来替换;

四、redis 雪崩

1、前提:产生了并发请求,并且有大批量的key同时失效了;

 2、分析:

  • 这里要区分你的业务场景,你的缓存具不具有时点性,如果不具有时点性当然随机过期时间就可以解决;如果具有时点性,我的redis大批量的key就要在一天内的某个点全部失效,这里只能强依赖于击穿的解决方案,引入分布式锁;

3、解决方案:

 五、总结

无论是redis的击穿、穿透还是雪崩,他们产生的前提都是存在并发请求,并且redis都未拦截到请求,导致大量的请求到达数据库,从整体的一个角度看我们主要解决的就是阻止大量的并发请求同时到达数据库。

一、前言

从架构的一个整体性来看,redis产生击穿、穿透、雪崩的情况的前提条件都是redis做缓存使用,并且产生了高并发,正常情况下我们利用关系型数据库(mysql、oracle等等)作为数据存储,如果并发量不大的情况完全可以hold住客户端的请求,如果高并发产生关系型数据库I/O就会成为瓶颈,这时会导致请求响应缓慢,严重会导致DB直接瘫痪。这时就要想尽一切办法阻止大量请求直接到达数据库,所以无论是Nginx限流、网关的限流、server层的降级处理、redis的缓存,唯一目的就是阻止大量请求直接到达DB。下面我们在这些理论的基础上讨论一下redis的击穿、穿透、雪崩。

二、redis的击穿

1、前提:redis肯定做缓存使用,并且key过期。【注意】这里是key失效,不是key不存在;

 2、分析:

redis只要做缓存使用一定会受到内存大小的限制,所以我们在使用redis做缓存时,无论是缓存key的过期时间到了还是redis内部的淘汰策略(LRU LFU) 都会有缓存失效的一瞬间,如果偏偏就是那么巧,在key失效的时大量的并发请求到达server ,然而此时缓存不存在,导致大量请求到达DB。这就是产生击穿的原因。

3、解决方案:

3.1、redis是一个单进程单实例的。所以并发请求都死排着队进入redis的,所以分为以下几个步骤:
  • 第一个请求进来发现没有key,立刻使用setNx(相当于一把锁);
  • 如果设置成功访问数据库,失败则睡眠一会再访问;
3.2、当然上面的方法会产生死锁的可能(如果第一个请求挂了),解决方法:
  • 设置锁的同时添加过期时间,如果超时自动释放锁资源;
  • 这里也存在一个问题那就是过期时间设置大小的问题,设置大了,如果第一个请求挂了,会导致后面的大量请求等待时间过长而超时,如果设置时间过短,自己没处理完别的请求进来了,这样循环下去,这也会存在一定的并发请求。
3.3、解决过期时间长短问题:
  • 可以开启一个守护线程来监控数据有没有从DB中获取出来放入缓存,如果没有完成则给锁续时间;
  • 可以使用已经封装好的 Redisson;
  • 同时也看到了redis实现分布式锁的复杂性,所以这里你也可以使用zookeeper来实现分布式锁;

三、redis穿透

1、前提:肯定发生了高并发,并且客户端请求的数据数据库不存在,更别期望缓存会存在。

 2、分析:

  • 举个例子你是一个卖家电的电商平台,别人就在你的客户端恶意并发请求母婴产品,这时就会导致大量的并发请求到达DB,造成数据库压力过大。

3、解决方案:

  • 使用布隆过滤器,这里你可以有几种集成的方案:1、直接放在客户端算法+bitmap;2、客户端只包含布隆算法,把bitmap放在redis中;3、redis集成布隆模块;

 

  •  当然布隆过滤器存在一个问题,就是只能添加不能删除,如果你可以容忍这个问题,ok 直接使用没问题,如果不能容忍,可以使用布谷鸟等其他过滤器来替换;

四、redis 雪崩

1、前提:产生了并发请求,并且有大批量的key同时失效了;

 2、分析:

  • 这里要区分你的业务场景,你的缓存具不具有时点性,如果不具有时点性当然随机过期时间就可以解决;如果具有时点性,我的redis大批量的key就要在一天内的某个点全部失效,这里只能强依赖于击穿的解决方案,引入分布式锁;

3、解决方案:

 五、总结

无论是redis的击穿、穿透还是雪崩,他们产生的前提都是存在并发请求,并且redis都未拦截到请求,导致大量的请求到达数据库,从整体的一个角度看我们主要解决的就是阻止大量的并发请求同时到达数据库。