一. 概念

redis击穿或者穿透有一个前置条件:一定是高并发的情况下才会发生。

        一般系统的架构设计会在ngnix或者其他微服务设计下阻拦很多的并发量,但是难免访问到redis的并发量还是很多,此时才会出现击穿问题。

击穿:redis曾经拥有,但是后来失去了,KEY的过期导致并发访问数据库

        我们知道redis中的数据key是有失效时间的,或者redis本身也是有淘汰机制的,假设redis中的数据key正好失效或者LRU、LFU淘汰机制把key_value淘汰掉了,假设此时正好并发线程去访问这条数据,redis中没有,只能把大量的请求怼到数据库上,这就是redis击穿。

雪崩:击穿比较侧重某一个key失效,当大量的key同时失效,会造成大量的请求怼到数据库,
就会发生雪崩效应。
重点是大量、同时两个词
穿透:redis本就没有,请求直接全部怼到数据库上,奈何数据库也没有,
导致数据库长时间做无效的连接查询造成损耗。

所以击穿和穿透的区别就出来了:

        击穿:redis中有需要的数据但是过期或者被淘汰了,导致直接全部访问数据库;

        穿透:redis中没有需要的数据,而且数据库中也没有需要的数据。

二.怎么解决击穿问题

  1. 首先redis都是单例单线程;
  2. 并发线程全部访问redis;
  3. redis中要访问的数据key失效或者数据被清除,无法获取数据;
  4. 此时通过setnx命令实现锁机制:SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
    1. EX 到期时间(以秒为单位)
    2. PX 到期时间(以毫秒为单位)
    3. NX 仅在键不存在时设置
    4. XX 只有在键已存在时才设置
  5. 此时的多线程分成了两部分,一个线程命令执行成功,那我们就允许他去访问数据库获取数据,另外一部分命令未执行成功,设置这部分睡眠一会儿,睡眠结束之后继续从步骤1开始执行。假设睡眠的线程执行到setnx命令,之前访问数据库的线程还未结束,也就是还没有释放锁,那么他们再次进行睡眠;
  6. 访问数据的哥们拿到数据之后,更新redis。睡眠的线程再次访问redis拿到需要的数据随即返回结果。

三.解决击穿问题过程中可能出现的问题

访问数据库的哥们中途挂了怎么办?可能出现死锁问题

        通过setnx实现锁机制,若在访问数据库的过程中线程挂掉了,就会导致锁无法释放,其他睡眠的线程始终无法再次拿到锁,形成死锁;

        解决方法:setnx命令可以设置锁到期时间,一旦线程挂掉,设置时间结束之后锁释放,其他睡眠的线程可以再次拿到锁访问数据库

数据库访问时间大于锁过期时间会造成数据库阻塞问题

        锁的过期时间设置了,访问数据库的线程没有挂掉,但是访问数据的时间大于设置的锁过期时间,也就是锁已经过期了但是数据还未查询到,此时就会有新的线程拿到锁再次访问数据库,从而造成阻塞。

        解决方法:使用多线程。再访问数据库的同时,重启一个线程去查询锁的过期与否,一旦发现锁过期,刷新锁的过期时间达到延长锁时间的效果

四、怎么解决雪崩问题

这个问题的解决得分两种情况:

1、我这个redis中的key同时失效是必须的,例如贷款利率因为政策问题,某一天的零点必须全部改变,或者优惠券在零点必须全部下架;

解决方案:

        a、在业务层增加判断,当时间到达零点的时候所有的请求随机睡眠一点时间(几毫秒或者更小),这样访问redis缓存的请求时间就会变得不一样,减少同一时间大量的访问;

        b、配合击穿时的解决方案,在访问redis时通过setnx实现锁机制,第一个访问数据库的线程只要把更新后的值同步到redis中,后续的请求就可以直接访问redis。

2、我这个redis中的key同时失效时点性不强。

解决方案:可以将redis中的数据key设置随机的失效时间,减少同时大量失效的情况。

五、怎么解决穿透问题

布隆过滤器

1、布隆过滤器的原理:

        a、首先你的数据库中有什么数据;

        b、布隆过滤器中包含固定大小的二进制向量或者位图(bitmap)和一系列映射函数

        c、通过布隆算法(多个映射函数)转换成多个二进制位标记到bitmap的数组中;

        d、接收请求时,要查询的数据同样转换成二进制位与bitmap中的进行对比,没有就直接返回,有就过滤掉去查询缓存,缓存查不到的话再去查询数据库;

        f、由于hash冲突的原因,可能存在一种情况:要查询的数据通过hash算法得到的二进制位正好在bitmap中存在,但是数据本身在数据库中是不存在的,这是这个请求仍然会被放行,使其去访问数据库,所以布隆过滤器也是一个概率解决问题,并不能百分百解决问题,但是放行的概率小于1%

        g、针对d中的情况可以配合布谷鸟过滤器使用,另外布谷鸟过滤器还存在一个del方法,支持数据的删除。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐