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

Redis缓存雪崩和击穿问题怎么破,聊聊那些实用又不完美的办法

聊到用Redis做缓存,大家肯定都听说过缓存雪崩和缓存击穿这两个词,听起来挺吓人的,像是系统快要崩溃了似的,它们确实都是高并发场景下容易遇到的坑,但解决思路其实很生活化,就是一些“头疼医头,脚疼医脚”的实用办法,而且每个办法都谈不上完美,需要根据实际情况做权衡。

先说说缓存雪崩

缓存雪崩这个名字很形象,你可以想象一下,冬天山坡上的积雪本来很稳定,但如果突然天气回暖,或者有个什么震动,大量积雪一下子全部滑落下来,那冲击力是毁灭性的,在Redis里,缓存雪崩就是指在某个时间点,缓存中大量的数据同时过期失效,或者更极端一点,Redis缓存服务器本身宕机了。

这时候会发生什么?瞬间,所有原本应该由缓存承担的请求,像洪水一样直接冲向了后端的数据库,数据库的连接数是有限的,处理能力也远不如内存操作的Redis,这么巨大的请求量一下子压过来,数据库很可能直接被打挂,导致整个系统瘫痪,这就是雪崩的可怕之处,它是由“量变引起质变”的连锁反应。

那怎么破呢?

  1. 给过期时间加个随机数。 这是最常用也最简单的办法,既然同时过期是祸根,那我们就不让它们同时过期,在设置缓存过期时间时,不要所有数据都设置成一样的,比如都设置成1小时,可以在1小时的基础上,加上一个几分钟的随机值,有的数据1小时1分钟过期,有的1小时5分钟过期,这样就能把大量缓存失效的时间点打散,避免它们在同一时刻集体失效,给数据库的压力也就从一个巨大的洪峰变成了持续的小浪花,这个办法很简单,但不能解决Redis本身宕机的问题。

  2. 设置热点数据永不过期。 对于一些极其关键、访问频率非常高的热点数据,我们可以考虑不设置过期时间,让它们永远待在缓存里,我们启动一个后台任务,定期去更新这些数据,这样就从“被动失效”变成了“主动更新”,彻底避免了因过期而产生的雪崩风险,但这个办法的缺点是需要额外的后台逻辑,而且如果数据更新不频繁,可能会有一段时间的数据不一致,如果Redis宕机,这个办法也无效。

  3. 构建缓存集群,保证高可用。 这是解决Redis自身宕机导致雪崩的根本方法,不要只用一个Redis实例,而是搭建Redis集群,比如Redis Sentinel(哨兵)模式或者Cluster模式,这样即使有一个或多个节点挂掉,其他节点还能继续提供服务,系统整体仍然可用,但这无疑增加了系统的复杂度和运维成本。

    Redis缓存雪崩和击穿问题怎么破,聊聊那些实用又不完美的办法

  4. 使用熔断降级机制。 这是一种“壮士断腕”的防守策略,当系统检测到数据库压力巨大,快要撑不住的时候,可以主动“熔断”,即暂时停止部分非核心服务的访问,或者直接返回一个默认值(服务繁忙,请稍后再试”),从而保住核心服务和数据库不崩溃,这就像电路里的保险丝,电流过大时自己先熔断,保护后面的电器,这显然会影响用户体验,属于一种有损策略。

再来聊聊缓存击穿

缓存击穿和雪崩有点像,但关注点不同,雪崩是“大面积”失效,而击穿是“单点”被击穿,它指的是某一个非常热点的数据(比如某个顶流明星的新闻)突然过期了,就在它失效的瞬间,海量的请求同时涌来,都发现缓存里没有这个数据了,于是所有这些请求都直接去查数据库,就好像一颗子弹打穿了缓存这层屏障,直接命中数据库,这个热点Key就像一个瓶颈,虽然只是一个点,但并发量极高,同样可能压垮数据库。

对付缓存击穿,也有一些针对性办法:

  1. 设置永不过期。 和应对雪崩一样,对于明确的、极其热点的Key,可以直接设置为永不过期,通过后台任务更新,这是最有效的方法,前提是你得能准确识别出哪些是这种“关键人物”。

    Redis缓存雪崩和击穿问题怎么破,聊聊那些实用又不完美的办法

  2. 加互斥锁。 这是一个非常经典的分布式锁应用场景,当第一个发现缓存失效的请求到来时,它不去直接查询数据库,而是先去获取一个锁(比如用Redis的setnx命令),只有拿到锁的那个请求才有资格去数据库查询数据并重建缓存,在这个过程中,其他并发请求如果发现没拿到锁,就等待一小段时间,然后重新去缓存里查询,这样一来,对数据库的请求就从成千上万个变成了只有一个,压力骤减,这个办法的缺点在于,没拿到锁的线程需要等待,会增加一些延迟,而且如果拿锁的请求在更新缓存时失败,可能会出问题,锁的实现本身也有复杂度。

  3. 缓存预热。 如果你能预知某个时点会有一个热点事件(比如双十一大促、热门商品开卖),可以提前把这个热点数据加载到缓存中,并合理设置其过期时间,避免在活动开始的关键时刻发生缓存失效。

总结一下

你会发现,这些办法没有一个是十全十美的“银弹”。加随机数能缓解但不能根除;永不过期避免了失效但增加了复杂度和不一致风险;集群解决了可用性但成本高;熔断是最后的保底措施但影响体验;加锁保证了数据库安全但牺牲了部分性能。

在实际工作中,我们通常不会只选用一种方法,而是组合使用,对大部分数据采用“过期时间加随机数”的策略,对少数核心热点数据采用“永不过期+后台更新”,同时整个系统搭建Redis集群保证高可用,并在网关或服务层配置熔断降级策略,这样一层一层的防御,才能构建起一个既高效又相对健壮的缓存系统,理解了这些办法的原理和优缺点,就能根据自己业务的实际情况,做出最合适的选择。


引用来源说明:综合参考了互联网上广泛的技术讨论,特别是来自开源社区、技术博客(如CSDN、掘金、InfoQ等)以及《Redis设计与实现》等书籍中关于缓存典型问题的常见解决方案,并非源自单一特定文献。