大家好,我是练习两年半的Java练习生,今天我们来讲一讲redis中常见的缓存问题
首先,我们先来缕一缕缓存穿透 、 缓存击穿、 缓存雪崩这三者到底有什么区别 ?
有时候我们看时就觉得自己会了,但回过头就忘了。今天就带大家来缕一缕
缓存雪崩
缓存雪崩是比较好理解的,就是在同一时间有大量的key值失效,导致大量请求打到数据库层面上。这跟真正的雪崩差不多。
大家可以想象真正的雪崩,必须是很多雪(key)同时脱落。
缓存击穿
缓存击穿 , 一个热点key失效,大量并发请求对其中进行访问,导致大量请求打到数据库上。
这个可以想象万军丛中,当很多人都攻击你的盾(热点key )时,突然这时候你的盾破了,你(数据库)就要被很多刀枪伺候了。
缓存穿透
缓存穿透,恶意攻击者通过请求Redis中本就不存在的key值,那么这种请求将直接打到数据库上,导致数据库压力变大。
这种情况就好比,你拿着盾,别人从背后偷袭你,你就防不胜防了
好啦,这下子我们妈妈再也不用担心我们弄混缓存穿透、缓存击穿、缓存雪崩问题了。接下来就让我们一起分析如何解决这三种问题吧!
针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用。
看似很简单是不是?
但这样做的坏处是什么呢?
对,很明显,这样做是很浪费空间的,而且我们浪费的是我们宝贵的内存空间!
那有没有更好的方法呢?
肯定是有的,那就是在请求进入redis之前进行非法请求的过滤,比如校验ip、设置防火墙等等
但我们除了缓存空值这种方法之外,也有一种更高级的方法,能更好的过滤请求,就是接下要介绍的布隆过滤器
在请求进入redis之前,会先根据布隆过滤器判断数据库中是否有该数据,有才进入redis查询,没有的话就直接返回。存在误判情况!
查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据。
布隆过滤器的原理是,当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组中的 K 个点(offset),把它们置为 1。
检索时,我们只要看看这些点是不是都是 1 就(大约)知道集合中有没有它了:如果这些点有任何一个 0,则被检元素一定不在;如果都是 1,则被检元素很可能在。这就是布隆过滤器的基本思想。
布隆过滤器可以 100% 判断元素不在集合中,但是当元素在集合中时可能存在误判,因为当元素非常多时散列函数产生的 k 位点可能会重复。
假设:
在创建布隆过滤器时我们为了找到合适的 m 和 k , 可以根据预期元素数量 n 与 ε 来推导出最合适的 m 与 k 。(推到过程过于复杂,没看懂,想了解的见文末)
在实践中,我们不用自己去实现,已经有可用的api。像java 中 Guava, Redisson 都已经实现了。
后面有机会向大家介绍。
如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
上面已经介绍过了,那么我们可以通过
面试官:那如何实现互斥锁呢?
互斥锁的实现可以利用我们redis中的SETNX命令。
通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存
当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
发生缓存雪崩有两个原因:
方法有以下几种:
好啦,以上就是我们今天要介绍的全部内容,希望能帮助你搞清楚缓存穿透、缓存击穿、缓存雪崩。如果有什么问题,欢迎在评论区讨论,一起学习进步!
https://xiaolincoding.com/redis/cluster/cache_problem.html#redis-%E6%95%85%E9%9A%9C%E5%AE%95%E6%9C%BA
https://en.wikipedia.org/wiki/Bloom_filter