细说缓存雪崩-击穿-穿透

      在我们的项目中,可能是tomcat活着rpc服务,当请求过来的时候,都会先判断cache中是否存在你想要的数据,如果存在,就直接返回给调用端,如果不存在,就会先查询数据库,然后缓存到cache中,然后返回结果给调用方。下次查询过来的时候,就可以命中缓存。但是会存在一些极端情况,包括缓存雪崩,缓存击穿,缓存穿透。


缓存雪崩:

    如果大批量的key在同一时刻失效,有可能会导致大批量的请求在同一时刻打到后台数据库,因为数据库的吞吐量是有限的,很有可能把数据库打垮,这种情况就是缓存雪崩。尤其是定时任务在批量设置cache的时候,一定要注意过期时间的设置。

如何预防缓存雪崩:

     1. 批量设置cache缓存时间的时候,给设置的缓存时间,设置一个随机数(随机数可以是10分钟内的数字),这样就不会出现大量的key在同一时刻集体失效。

     2. 如果真的发生了雪崩,流量不是很大的情况下,数据库可以扛得住。如果流量很大,很容易把数据库搞宕机。这个时候就需要引入限流方案,当达到限流设置的参数的时候,就拒绝请求,从而保护后台db。限流还分为本地限流和分布式限流两种。后面会专门写一篇文章介绍本地限流和redis实现的分布式限流。

缓存击穿

     对于热点key,如果cache失效,就会导致瞬间这个key的流量涌向数据库,这种情况就是所谓的缓存击穿。至于热点key为什么会失效,可能是到期了,也可能是内存不够淘汰掉了。

如何解决缓存击穿

     1. 限流: 主要就是限制热点key的流量,当这个key被击穿后,限制只有一部分流量进入到db,其他都被拒绝或者等待重试查询redis。限流分为本地限流和分布式限流。本地限流就是在单个实例范围内,限制这个key的流量,只对当前实例有效。分布式限流就是在分布式环境下,多个实例范围内,这个key的流量累加来自多个实例的流量。

     2. 分布式锁: 当多个请求进来的时候,只有一个请求可以获取到分布式锁,进行查询和设置cache,其他的请求可以直接返回空值给客户端,或者等待一定的时间再次查询redis.

    3. 定时任务更新热点key:

       说白了,就是一个定时任务定时去监控热点key的超时时间,是否到期,在进行快到期的续期操作。

      单线程轮询方式进行检查和更新失效时间:

       

     多线程方式:如果热点key很多,可以采用线程池方式:

     

     延迟队列实现:

       上面两种方式,无论单线程还是多线程,都会采用轮询的方式来检查key是否快到期了,这会导致cpu资源浪费。这种方式检查会存在检查时间不准确,可能会造成时间的延迟或者不准确,你在等待进行下次检查的时候,这个key就没了,那么此时已经造成了击穿。这种情况发生的概率低,但是也有可能发生。其实可以利用延时队列或者时间轮解决这个问题。

     1、程序首次启动 获取名单内key的失效时间。
     2、依次设置key 延迟消费的时间,注意这个消费时间要比失效时间要早。
     3、延迟队列到期,消费端进行消费key。
     4、消费端消费消息,延迟key的失效时间到cache。
     5、再次发送key 新的失效时间到延迟队列,等待下次延迟cache的失效时间。

4. 设置key永不失效

     这种其实可能会因为内存不足导致key被淘汰。

缓存穿透

    所谓缓存穿透,就是访问一个cache不存在,数据库里面也不存在的key,那么此时流量会直接打到db,如果因为别人疯狂用这个不存在的key刷接口,可能会把DB打垮。导致业务不能正常运行。

解决办法

  1. 设置null或者特殊值

  可以通过设置null或者特定的值到redis内。 这种办法其实不能解决根本问题,如果这个流量能仿造大量的无用key,设置再多的null或者特殊值都是没有用的。

  2. 布隆过滤器

    我们可以利用一个bit的数组,来存储这个sku是否存在状态,0 代表不存在,1 代表存在,我们可以利用一个散列函数,算出sku的散列值,然后sku的散列值对bit数组进行取模,找到所在数组的位置,然后设置为1,当请求来的时候,我们会算出这个sku 散列值对应的数组位置是否为1 ,为1 说明就存在,为0 说明就不存在。这样一个简单的bloomfilter就实现了,bloomfiler 是有错误率,可以考虑增加数组长度和散列函数的数量来提供准确率,具体可以百度或者google,今天在这里就不讲了。

      如果不利用布隆过滤器,对于数据库根本不存在的key,会白白浪费两次IO,一次查redis,一次查DB。有了布隆过滤器,可以节省两次无用的IO,减少后端redis和db的资源浪费。

3. 网关限流

     我们都知道正常用户是不会在单位时间内发起那么多次请求的,那么我们可以在网关层NGINX进行设置,对单个IP每秒访问次数超出阈值的IP放到黑名单。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值