缓存击穿,缓存穿透,缓存雪崩的原因
- 缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
- 缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
- 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
缓存击穿的解决方案
使用互斥锁(mutex key)业内常用
若有大量的请求直接打到数据库上,会导致数据库崩溃,那么就先用redis互斥锁,使得所有的请求只有一个请求能拿到资源,等查到数据后,再将数据写回缓存。
其余的请求申请不到锁的时候,意味着已经有请求拿到资源了,所以只需要sleep一段时间(等数据写入缓存),再次去读取缓存即可。
让redis的key永不过期(可行但不好)
- 设置key永不过期,在修改数据库的时候,同时更新缓存。
- 在key将要过期的时候,去更新这个key,延长他的过期时间。
- 分级缓存,一级缓存失效,还有二级缓存垫背。
为什么不好?因为数据的量巨大,我们的 redis 缓存,是基于内存的,一个单点,一般也不会分配过大的内存,来保证它足够灵活。
如果永不过期,那么redis就会越来越臃肿,没有初衷了。
使用redis锁的解决方案思路图:
针对互斥锁的思路完善这个解决方案
问题1
如果用户请求完锁之后还没来得及释放就挂了,那么锁就会一直被占用,后面的用户就不能正常工作了。
解决方案:给这个锁设置过期时间,保证无论如何一定会被释放。
问题2
如果用户请求完锁之后,锁到期了依旧没有完成业务,那么其余的用户就会抢占这个锁,互相卡来卡去超时。
解决方案:开一个线程去监控锁的过期时间,如果锁临近过期了还没完成事务,就会延长锁的过期时间。
应用:Redisson自带的看门狗函数。
问题3
如果碰见redis集群的场景,且申请锁的redis挂了,那么就会影响redis的主从一致性。
解决方案:加锁的 redis 结点,只要满足,N/2+1,也就是过半,即代表加锁成功。(Redlock)
在整个加锁过程中,整个加锁的过程,不能超过锁的有效时间,否则,就应算作加锁失败,要立刻清除所有单独结点上的锁。
缓存穿透的解决方案
布隆过滤器
将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
用bitmap,采用多次哈希的方式,每一次哈希都往一个槽位写上 1; 当来查询一个不存在的 key 的时候,就可以进行同样的多次哈希,第一次可能碰巧撞对,得到 1,但是后面还有两次,这样,就不一定有那么好的运气,还能够撞对。 因此,这样,可以降低缓存穿透的概率。
布隆过滤器的示意图
无效值也加入redis
比较简单的,就是选择,当用户查询不存在的数据时,将这个 key,存入 redis,然后用一个特殊的 value 来表示,这是一个不存在的数据。
缺点:但是,如果有大量的请求,都请求各不相同的不存在的数据,那么,redis 的缓存,就会用来存储大量没用的数据,就会造成空间的浪费。
缓存雪崩的解决方案
有一个简单方案就时将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
或者Redis查DB数据的时候将请求加一个随机延迟时间,让请求不要集中。
一般随机失效时间就已经能完成任务了,但是如果有强更新强同步的需求(12点清空数据等)。
第二个随机延迟时间的方法能完成需求,因为随机延迟时间请求,一方面能降低请求的压力,第二方面第二波请求可以从redis读取数据,进一步降低压力。
标签:缓存,请求,过期,Redis,redis,雪崩,key,解决方案 From: https://www.cnblogs.com/xiaochaoheni/p/17693938.html