Redis常见面试题(缓存击穿、穿透、雪崩)
击穿
场景:
一般由于redis中的数据到期,同时并发用户特别多,此时大量请求压到数据库上。
解决思路:
根据redis是单进程单实例的特性,当高流量进入redis时,可以认为是在队列中依次执行,当请求发现key过期时,可以设置锁。
流程:
- 请求到达redis,发现key过期,查看是否有锁,如果没有回到队列排队。
- 设置锁,用setnx(),也就是当key不存在时再设置,防止其他线程已经设置锁。
- 拿到锁后去数据库中取数据,返回后释放锁。
问题1:
如果拿到锁以后的请求挂掉了,但是锁没有释放,会造成其他请求一直在等待锁的释放。
问题1解决方法:
对这个锁加过期时间,到了过期时间还没释放,就自动释放。
问题2:
如果请求没挂掉,但是锁的过期时间已经到了,数据还没取出来,会导致其他请求又设置锁,进入数据库取数据。。。
问题2解决方法:
再开启一个线程,对第一个取数据的线程进行监控,如果没挂掉,就适当延长锁的过期时间。
穿透
场景:
大量请求访问redis以及数据库中没有的数据,导致异常流量到达数据库查询返回null的结果。
解决思路:
加过滤器,拦截异常请求。
流程:
在客户端实现布隆过滤器的算法,或者直接在redis中集成布隆过滤器。同样的过滤器还有布谷鸟过滤器等。
雪崩
场景:
大量的key同时失效,造成大量访问压到数据库上。
解决思路:
首先要区分失效的key是否和时点性相关,然后采取不同的解决办法。
流程:
- 如果是和时点无关的数据,可以采取给key加随机的过期时间。
- 如果是和时点有关的数据,如到凌晨0点必须统一失效的key,不能使用随机过期时间,否则到凌晨0点时会读到之前的数据,也就是脏数据。可以强依赖击穿的解决方法。先过去的线程更新key,业务层对其他请求做延迟,睡几十毫秒或者秒。
Redis做分布式锁
- 通过setnx()加锁。
- 给锁加过期时间。
- 通过多线程监控,适当延长锁的过期时间。
- 以上三点是解决思路,实现过程较为麻烦,最好通过zookeeper做分布式锁(关于zookeeper内容可以订阅zookeeper专栏)。