Redis 缓存三连击
- 缓存雪崩
- 同一时刻出现大规模缓存key失效,那么大量的请求就会打到数据库造成压力,高并发的情况下数据库可能会宕机。
- 缓存击穿
- 和缓存雪崩相似,缓存雪崩是大规模key同时失效。而缓存穿透是一个热点key失效,并且有并发集中的对其进行访问,导致大量并发打到数据库,导致数据库压力剧增。
- 缓存穿透
- 缓存中不存在数据数据库也不存在数据,在这种情况下大量这样的请求,这些请求就跟“穿透”一样穿过缓存打到数据库。
关于缓存击穿和缓存穿透,很多人都会搞混。
你换一个记法,缓存戳穿、缓存戳透。
穿,只是穿过了缓存。
透,是直接干到底。
你细品,应该就不会记混。
缓存击穿
先说一下缓存击穿的概念。
缓存击穿是指一个请求要访问的数据,缓存中没有,但数据库中有的情况。
这种情况一般来说就是缓存过期了。
但是这时由于并发访问这个缓存的用户特别多,这是一个热点 key,这么多用户的请求同时过来,在缓存里面没有取到数据,所以又同时去访问数据库取数据,引起数据库流量激增,压力瞬间增大,直接崩溃给你看。
所以一个数据有缓存,每次请求都从缓存中快速的返回了数据,但是某个时间点缓存失效了,某个请求在缓存中没有请求到数据,这时候我们就说这个请求就"击穿"了缓存。
有三个解决方案
第一个方案就是只放行一个请求到数据库,然后做构建缓存的操作。
就借助 Redis setNX 命令设置一个标志位就行。设置成功的放行,设置失败的就轮询等待。
意思就是,先放行一个请求进去重构缓存,然后其他请求轮询等待重构缓存成功。
第二个解决方案就是后台续命。
这个方案的思想就是,后台开一个定时任务,专门主动更新即将过期的数据。
比如程序中设置 why 这个热点 key 的时候,同时设置了过期时间为 10 分钟,那后台程序在第 8 分钟的时候,会去数据库查询数据并重新放到缓存中,同时再次设置缓存为 10 分钟。
第三个方案就简单了:永不过期。
缓存为什么会被击穿,是不是因为设置了超时时间,然后被回收了?
那设置TTL永不过期就好了。
结合实际场景,这个key肯定是热点key,会有大量请求来访问这个数据,而且这个key和vlaue不会经常变化或者是不会发生变化。
黑马的店铺缓存就是采用永不过期加上vlaue里面写入了逻辑过期时间。逻辑过期时间判断过期就会返回旧数据出去,同时会开启一个独立的线程去重构数据查询拿到新的数据并更新逻辑过期时间。
这个就和后台续命差不多。
总之,具体情况,具体分析。
但是思路要清晰,最终方案都是常规方案的组合或者变种。
缓存穿透
那么啥又是缓存穿透呢?
缓存穿透是指一个请求要访问的数据,缓存和数据库中都没有,而用户短时间、高密度的发起这样的请求,每次都打到数据库服务上,给数据库造成了压力。
一般来说这样的请求属于恶意请求。
就比如说,我这是一个技术公众号,你明明知道我没有,但是你非要来我这里买一瓶啤酒,恶意请求。
怎么解决呢?
两个方案。
第一个方案缓存空对象。
就是在数据库即使没有查询到数据,我们也把这次请求当做 key 缓存起来,value 可以是 NULL。
下次同样请求就会命中这个 NULL,缓存层就处理了这个请求,不会对数据库产生压力。
这样实现起来简单,开发成本很低。
**面试题:**对于恶意攻击,请求的时候key往往各不相同,且只请求一次,那你要把这些 key 都缓存起来的话,因为每个 key 都只请求一次,那还是每次都会请求数据库,没有保护到数据库呀?那就看第二个方案
黑马的实现流程
第二个方案布隆过滤器。
布隆过滤器的特性是某一个值存在时,这个值可能不存在。当它说不存在的时候,那就一定不存在。
也就是说会存在误判的可能,但可以抵挡大部分的恶意请求。
缓存雪崩
缓存雪崩是指缓存中大多数的key在同一时间过期,而查询数据量巨大,这个时候,又是缓存中没有,数据库中有的情况了。请求都打到数据库上,引起数据库流量激增,压力瞬间增大,直接崩溃给你看。
和缓存击穿不同的是,缓存击穿是指大量的请求并发查询同一条数据(热点key)。
缓存雪崩是指不同是数据都到了过期时间,导致在缓存中查询不到。
还有一种情况redis挂了也算缓存雪崩。
解决方案。
将key的过期时间,再加上一个短而随机的过期时间,这样可以避免大量的缓存在同一时间过期,造成缓存雪崩。
缓存雪崩只能预防,如果想要实现高可用就需要集群、哨兵、主从的模式去保证redis的高可用。
这篇文章借鉴了 知乎大哥的https://www.zhihu.com/collection/438154066。然后流程图是黑马的。学习笔记啦