Redis的缓存雪崩、穿透、击穿

Redis的缓存雪崩、穿透、击穿

缓存雪崩

高并发条件下,大面积的缓存key在同一时间失效,导致sql负载过高而宕机。
解决方案:

  1. 不同的key,设置不同的失效时间,让缓存失效的时间点尽量均匀(可采用随机)
  2. 在缓存失效后,通过加锁或者队列来控制读取数据库写缓存的线程数量
  3. 通过缓存reload机制,预先去更新缓存,在即将发生大并发访问前手动触发加载缓存(定时任务)
  4. 使用二级缓存或者双缓存策略,使用redis集群部署,将热点数据均匀分布在不同节点,单个节点宕机可从其他节点上获取相关数据

缓存穿透

对于redis缓存和数据库中不存在的数据,因为redis中没有对应数据,无法进行拦截,请求会直接被穿透到数据库。若有人恶意进行破坏,进行高并发请求不能存在的KEY,会导致数据库压力过大而宕机。
解决方案:

  1. 使用布隆过滤器(将所有可能存在的数据hash到一个足够大的bitmap,一个一定不存在的数据会被这个bitmap拦截),不存在的key会被布隆过滤器过滤,从而减轻数据库的压力
  2. 对不存在的数据也缓存到redis里,设置value为null
    - 缓存太多空值,占用更多时间(优化:设置为短期失效)
    - 存储层更新代码了,缓存层还是空值(优化:后台设置时主动删除空值,并将值进行缓存)
    
  3. 其他:拉黑恶意IP、请求参数校验

缓存击穿

对于设置了过期时间的KEY,如果这些KEY可能在某些时间被高并发访问,成为热点KEY,失效的一瞬间,持续的高并发访问会击穿缓存直接访问数据库, 导致数据库压力骤升而宕机。
另外地,缓存的构建是需要一定时间的。(可能是一个复杂计算,例如复杂的sql、多次IO、多个依赖等等),于是就会出现一个致命问题:在缓存失效的瞬间,有大量线程来构建缓存,造成后端负载加大,甚至可能会让系统崩溃 。
解决方案:

  1. 使用互斥锁(mutex key):只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据
  2. “提前”使用互斥锁:在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。
  3. “永远不过期”:
    这里的“永远不过期”包含两层意思:
    (1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
    (2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期
    
  4. 资源保护:可以做资源的隔离保护主线程池,如果把这个应用到缓存的构建也未尝不可。

方案对比:
作为一个并发量较大的互联网应用,我们的目标有3个:

  1. 加快用户访问速度,提高用户体验。
  2. 降低后端负载,保证系统平稳。
  3. 保证数据“尽可能”及时更新(要不要完全一致,取决于业务,而不是技术。)

四种方案,可以做如下比较,还是那就话:没有最好,只有最合适。

解决方案优点缺点
简单分布式锁1. 思路简单
2. 保证一致性
1. 代码复杂度增大
2. 存在死锁的风险
3. 存在线程池阻塞的风险
加另外一个过期时间1. 保证一致性同上
不过期1. 异步构建缓存,不会阻塞线程池1. 不保证一致性。
2. 代码复杂度增大(每个value都要维护一个timekey)。
3. 占用一定的内存空间(每个value都要维护一个timekey)。
资源隔离组件hystrix1. hystrix技术成熟,有效保证后端。
2. hystrix监控强大。
1. 部分访问存在降级策略。

缓存使用与设计系列文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值