1. redis 击穿
原来有,后来失效了。击穿了
当redis作为缓存使用时,当key由于 失效时间过期 或者 LRU LFU算法 使得redis总的key失效后,突然有了高并发,此时,redis中没有这个key,到时并发去数据库获取数据。相当于击穿了redis,到数据库上了
解决的办法。
方法1: setnx 设置锁
假设有3个线程同时到达。
1. 先去get key 获取目标key 。此时获取的为nli
2. 设置锁 ,setnx lockkey lockvalue。 setnx 调用,当没有lockkey时才会创建成功,如果有,就不能创建。也就是说,只有setnx成功后,才能取访问数据库
可能三个线程都去get key都没有取到,由于redis是单线程的,所有只可能有一个线程setnx成功。其他的正在等待,知道第一个线程释放锁后,后面的线程才能够setnx成功。
3. 获取到锁的线程才能访问数据库。
以上方式也会有新的问题:
如果第一个线程获取到锁后,突然线程挂了怎么办。此时后面的线程就拿不到锁。
此时,我们可以给锁设置一个过期时间。当时间到了也能释放锁。
但是如果,线程没有挂,过期时间到了,锁已近释放了,但是查询数据库还没有结束,此时接下来的线程都会卡到查询数据这一步
解决办法: 一个线程取查询数据库
另一个线程监控是否数据取回来了,如果锁过期还没取回来,则更新锁的过期时间。
方法二: 设置热点数据用不过期
方法三:利用布隆过滤器
-
利用过滤器,布隆过滤器。Bloom Filter,用来判断一个key是否在集合中。
布隆过滤器原理:和hash表是一样的。-
需要一个bit位的数组,初始值位0,存储的key通过hash函数算出一个数,而这个数就是对应数组中的索引,将该索引位置设置为1,表示这个key是存在的。
-
所以将数据库中所有的查询条件放入到布隆过滤器中。
-
向查询redis,如果redis没有,查询布隆过滤器,key通过hash函数找到bit数组中的位置,如果该位置为0,表示集合中一定没有该值,直接返回。如果为1,表示这个值有概率在集合中,就可以放过查询数据库。
-
使用
eg: 1、 将所有数据都添加add到bloom过滤器中。BF.add 所有数据
2. 通过判断是否存在。如果返回为1, 就有可能存在,可以放过去数据库中查询。 BF.exist 判断是否存在,1 有可能有,0一定没有。
如果返回为0,就一定不存在,此时直接返回就可以了。
击穿图
2. 穿透
本身数据就不存在,直接穿透
1. 就是请求调用获取的key 在redis 和数据库 中都没有。就是业务需要查询的数据,数据库中根本没有,就是空。
解决问题 :
1)布隆过滤器。缺点,不能删除。使用 布谷鸟,可以删除
2)在接口层做一些校验,比如用户鉴权,或者一些范围的校验,进行拦截一部分
3)或者对于获取不到数据的,进行缓存一些null,但是设置的过期时间要小。
3. 雪崩
大量的key同时到期了,大量的key失效。大量的访问到达数据库DB。相当于换血。
雪崩和击穿有点相像。
但是有所区别: 击穿可以理解为个别数据的高并发
雪崩则是大量数据的高并发。
解决办法:1. 随机过期时间。时点性无关时适用
2. 还有一种场景就是,在零点(固定时间点)必须换key,此时就不适用随机过期时间,此时强依赖击穿方案。