关于redis缓存穿透/缓存击穿/缓存雪崩的理解和解决方案
一. 背景
我们一起来听听Redis缓存穿透、缓存击穿、缓存雪崩都是什么。
二. 缓存穿透
首先我们看看什么是“缓存穿透”。
2.1 概述
比如我们排在长长的队伍中等着做核酸, 如果在做的时候,突然没有棉签或者试管了,那么工作人员就会访问防疫指挥中心有没有;如果有防疫指挥中心也没有,那么就会告知核酸队伍。这种现象,可以理解为缓存穿透。
缓存穿透是指Redis中没有缓存数据,数据库中也没有对应的数据,业务系统每次都会绕过缓存服务器查询下游的数据库,缓存服务器完全失去了其应有的作用。
缓存穿透形成的原因,有可能是key写错了,也有可能是恶意攻击。下图红线就代表穿透的执行流程,缓存穿透会导致后端数据库负载加大,缓存层失去了应有的作用,高并发下可能会造成数据库的宕机。
既然存在缓存穿透的现象,那该怎么解决呢?
2.2 解决方法
方法1:缓存空值
如果某个核酸点没有核酸检测物料,比如试管,可以在第一次问询防疫中心,如果都没有的情况下,就会在这个核酸点贴出公告,告知做核酸的人员,这样后面排队的人就不用苦苦等待了。
对于数据缓存来说,如果在第一次查询时数据为空,我们就可以直接将null值缓存,但要设置一个较短的过期时间。这样,当db中有数据时,可以及时更新,或者利用mq发送异步消息,触发数据的Redis设置。
方法2:布隆过滤器(BloomFilter)
我们知道,一般核酸点,会有一个拿着喇叭的志愿者,当他告诉你没有物料时,你就没必要排队了!
而缓存穿透也有很多情况,很多是恶意访问造成的,这些请求可能会随机生成很多key,如果使用空值处理,会在redis中生成很多垃圾数据,这时我们可以使用布隆过滤器来进行解决。布隆过滤器是一种比较巧妙的概率性数据结构,它可以告诉你数据一定不存在或可能存在。相比Map、Set、List等传统数据结构,布隆过滤器占用的内存少、结构更高效。对于缓存穿透,可以将查询的数据条件都哈希到一个足够大的布隆过滤器中,用户发送的请求会先被布隆过滤器拦截,一定不存在的数据就直接拦截返回了,从而避免下一步对数据库的压力。
三. 缓存击穿
3.1 概述
现在又有另外一种情况,比如周六核酸时,核酸物料就比较紧张。假如在同一时间段内,有多个核酸点的试管都用完了,都会向防疫指挥中心索要物资。缓存击穿就有点类似于这种情况。
缓存击穿是指当某一个key缓存过期时,突然有大并发量的请求同时访问这个key,这有可能会瞬间击穿缓存服务器而去直接访问数据库,让数据库处于高负载的情况。DB负载过大,就可能会造成后端服务器宕机。尤其是在秒杀、大促的情况下,并发请求量过大,而key刚好又过期,缓存key对应的key值,计算又比较复杂,重新缓存到数据库也需要一段时间,这时就可能会压垮后端数据库。
3.2 解决方法
方法1: 异步定时更新(及时预防)
可以安排一个志愿者,专门管理核酸、物料,一旦总部有了,马上调拨。
放到我们的项目中,可以设置一个定时任务来检查DB。一旦DB中有了数据,就及时放入缓存。
如果遇到秒杀大促等高并发的场景,需要在缓存的key失效之前,重新进行缓存,相当于更新数据+延时。
方法2:分布式互斥锁
没有物料后,首先通知第一个做核酸的,然后询问防疫指挥进行调拨,并让志愿者进行喇叭通知,让其他排队的都进入到等待状态。
在处理缓存时,通常使用一个互斥锁来解决缓存击穿的问题。简单来说,就是当Redis中根据key获得的value值为空时,我们先给它锁上;然后再从数据库进行加载,加载完毕后再释放锁。若其他线程也在请求该key时,发现获取锁失败,则先阻塞。
四. 缓存雪崩
4.1 概述
缓存集中在一个时间内同时大量失效,就可能会发生大量的缓存穿透,此时查询都落在数据库上,造成数据库负载瞬间过高,严重影响性能,最后有可能导致数据库直接宕机。
4.2 解决方法
方法1:为key设置不同的过期时间
避免所有的key在同一时间过期,可以给不同的key设置不同的过期进间。
方法2:给DB做集群部署
可以对DB搭建集群,进行分流。
相关推荐HOT
更多>>怎么将string字符串转换成byte[]数组?
例如,使用默认字符集转换可以如下所示: 也可以指定字符集: 这将使用UTF-8字符集将字符串转换成字节数组。详情>>
2023-04-25 17:14:58如何禁用浏览器的前进和后退功能
URL) 本质就是在进入页面或者路由跳转的时候在历史记录中保存一条没有意义的记录,这样用户在点击前后后退按钮的时候就没有效果。详情>>
2023-04-19 10:36:58react传值是什么意思?
react是组件化的框架,组件实例间作用域是互相隔离的,所以组件间的通信就变成了开发过程中常常要解决的问题,根据场景可以分为: 父子组...详情>>
2023-04-18 17:23:22使用IE浏览器遇见过哪些兼容问题?
在IE6中,块元素设置float并且有水平方向的margin时,margin显示出来会比设置的值大,会导致最后一块元素被顶到下面去; 解决办法:在CSS文...详情>>
2023-04-12 09:21:12