当前位置:首页 > 问答 > 正文

Redis缓存击穿老问题,这次有点新办法能试试看,效果咋样还得用了才知道

(引用来源:文章“Redis缓存击穿老问题,这次有点新办法能试试看,效果咋样还得用了才知道”)

Redis缓存击穿这个问题,说白了就是当一个非常热点的数据,比如某个顶流明星突然官宣结婚的消息详情,在缓存里过期的那一刻,海量的用户请求一下子都涌了过来,直接冲垮了数据库,这就像演唱会散场时,唯一的出口突然卡住了一样,所有人都堵在那里,系统一下就瘫了,老办法比如用分布式锁,虽然能解决问题,但就像只开一个检票口,大家排长队,体验不好,而且锁本身也是个负担。

Redis缓存击穿老问题,这次有点新办法能试试看,效果咋样还得用了才知道

这篇文章里提到了一些新思路,我觉得挺有意思,不是那种教科书上的死板方案,更灵活一些,当然啦,具体效果真得在实际业务里跑跑看才知道。

第一个办法叫“逻辑过期”,这个想法挺巧的,它不再死板地依赖Redis自带的有效期,具体是这么干的:我们存进Redis里的数据,不再设置Redis本身的过期时间,而是把过期时间作为一个字段,和数据本身打包在一起存进去,比如存的是 {value: "真实数据", expireTime: 1730000000},当业务线程来读数据时,先取出这个包,检查一下里面的expireTime,如果没过期,太好了,直接返回value,如果发现过期了,那这个线程也不急着去查数据库,它先果断地抢一把锁。

Redis缓存击穿老问题,这次有点新办法能试试看,效果咋样还得用了才知道

抢锁这个环节是关键,抢到了锁的线程,就成了那个“天选之子”,它负责去数据库拉取最新数据,然后更新Redis里的这个数据包,同时重置一个新的未来过期时间,那其他没抢到锁的线程怎么办呢?它们不会傻等着,也不会直接去冲击数据库,它们会选择相信“天选之子”正在努力工作,于是会把刚才那个虽然逻辑上已过期、但数据内容还在的旧数据直接返回给用户,这样做,用户可能看到的是稍微延迟了一点的信息,比如明星官宣后一分钟内的旧消息,但总比系统卡死、什么都看不到要强得多,这种用少量延迟换取系统高可用性的思路,在很多对实时性要求不是极端苛刻的场景下,是非常划算的,这个办法的好处是,大部分请求根本感知不到后台的更新操作,非常平滑。

第二个办法是“预热与延期”,这个更适合那些我们能预判到的热点,比如电商平台定时上新的秒杀商品,或者重要新闻的发布时间点,既然知道某个时间点会火爆,那就提前做好准备,在缓存快要过期之前,比如提前一分钟,系统就主动去更新缓存,并把过期时间再延长,这样就能完美避开那个“缓存刚好失效”的危险时间点,甚至可以设置一个随机延长时间,比如基础过期时间是一小时,然后在55分钟到65分钟之间随机选择一个时间点来刷新和延期,这样就能避免大量热点key在同一时刻失效,把压力均匀分散开。

还有一种思路是“互斥锁的优化版”,虽然锁是老办法,但新思路在于优化抢锁失败后的行为,传统的做法是让没抢到锁的线程循环等待、重试,这其实很消耗资源,新的办法是,让这些线程短暂睡眠一个非常短的时间(比如几毫秒),然后不直接重试查锁,而是直接再去查一次缓存,因为很可能就这么一会儿工夫,那个抢到锁的“天选之子”已经把事情办妥了,数据已经重新塞回缓存里了,这样就避免了大量线程无谓地争抢同一把锁,减少了系统内部的无用功。

文章最后也提到了,这些办法都不是银弹,得看具体情况,逻辑过期”虽然好,但它会造成数据的短暂不一致,如果你的业务是金融扣款或者库存扣减,那绝对不能用这个方法,必须用强一致性的锁,而“预热与延期”则要求你对热点有预判能力,对突发性的热点就无能为力了。

说到底,技术方案的选择就像看病开药,得先诊断清楚自己业务的“体质”:是追求极高的可用性,可以容忍秒级的不一致?还是要求绝对的准确,哪怕慢一点也行?对热点数据的规律是否能够把握?把这些想明白了,再结合上面这些新办法、老办法,组合起来用,才能找到最适合自己的那味药,效果嘛,就像文章标题说的,确实得用了才知道,不上线压一压,永远不知道哪个环节会出幺蛾子。

Redis缓存击穿老问题,这次有点新办法能试试看,效果咋样还得用了才知道