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

Redis雪崩到底是啥情况,缓存突然全挂了咋办啊

你问的“Redis雪崩到底是啥情况,缓存突然全挂了咋办啊”,说白了就是一种连锁反应式的灾难,咱们用一个最生活化的例子来理解,就像双十一零点,所有顾客(用户请求)本来都是先去一个大展厅(Redis缓存)看样品,看完样品直接下单,这样就不用去挤爆仓库(数据库)了,这个展厅能极大地减轻仓库的压力。

Redis雪崩就是:这个样品展厅,在某个时间点,突然之间,里面绝大部分的样品,甚至所有样品,同时失效了,过期了,不见了。

想象一下这个场景:双十一零点刚过,几百万顾客同时涌进展厅,却发现他们想看的成千上万件商品的样品,偏偏都在这一刻齐刷刷地消失了,那会发生什么?这几百万顾客会怎么做?他们肯定会一窝蜂地冲向后方那个小小的、根本承受不住这么大流量的实体仓库(数据库),结果就是,仓库瞬间被挤爆,数据库的连接数被打满,CPU和内存使用率飙升到100%,整个系统瘫痪,页面打不开,订单下不了,所有服务都不可用了,这就是雪崩的可怕之处:缓存失效只是诱因,导致数据库被打垮,进而造成整个系统的崩溃。

为什么会出现这种“集体失效”的倒霉情况呢?主要有两个常见原因:

  1. 大量缓存key设置了相同的过期时间:这是最典型的人为失误,在系统上线时,为了图省事,给所有缓存数据都设置了一个默认的过期时间,比如晚上12点,有效期24小时,那么第二天晚上12点,所有这些缓存就会在同一秒内全部失效,如果这时候还有大量请求进来,灾难就发生了。(来源:常见的系统设计失误总结)
  2. Redis服务本身宕机:这就不是缓存过期的问题了,而是展厅直接关门大吉了,Redis所在的服务器断电了、网络出现严重故障、或者Redis进程因为某种原因崩溃了,这种情况下,所有请求同样会直接砸向数据库,效果和大量缓存同时失效是一样的。(来源:分布式系统故障模式分析)

那万一缓存突然全挂了,我们咋办呢? 这得分情况看,是“事前诸葛亮”还是“事后灭火队”。

缓存已经挂了,正在灭火(事后补救)

这时候系统已经瘫痪,数据库压力巨大,首要目标是保命,尽快恢复服务。

  1. 服务降级和熔断:这是最重要的应急手段,立刻启动预案,对非核心的业务功能进行降级处理,暂时关闭商品推荐、用户积分查询等功能,只保证最核心的下单、支付流程能勉强运行,在应用和数据库之间设置“熔断器”,当检测到数据库响应时间过长或错误率过高时,熔断器会直接“跳闸”,在一段时间内拒绝所有请求,给数据库喘息的机会,而不是任由请求把它拖死。(来源:微服务架构中的容错模式)
  2. 限流:在系统的入口层面进行严格的限流,正常情况下每秒能处理1万个请求,现在数据库顶不住了,就只允许每秒放1000个请求进来,剩下的请求直接返回“系统繁忙,请稍后再试”的友好提示,虽然牺牲了一部分用户的体验,但保证了系统不会彻底崩溃,大部分用户还能勉强使用,这就像地铁早高峰限流一样,是为了保证整个系统能运转下去。(来源:高并发系统设计原则)
  3. 快速恢复Redis服务:如果是因为Redis宕机导致的问题,首要任务当然是尽快重启Redis服务,重启后,虽然缓存是空的(冷启动),但结合上面的限流措施,可以让流量缓慢地重建缓存,而不是一股脑又冲垮数据库。

如何预防雪崩,不让它发生(事前设计)

灭火很重要,但更重要的是别着火。

  1. 设置随机的过期时间:这是解决“集体失效”最直接有效的方法,不要给所有缓存设置相同的过期时间,基础过期时间设为24小时,然后在这个基础上加上一个随机的几分钟或者负几分钟(24小时 ± 随机0-600秒),这样就能保证缓存不会在同一时刻全部失效,而是均匀地分散在一天的不同时间点失效,从而把对数据库的冲击降到最低。(来源:Redis官方最佳实践建议)
  2. 使用缓存永不过期策略:这个策略不是真的永不过期,而是指程序逻辑上的“永久”,具体做法是,我们不给缓存设置过期时间,而是让缓存一直存在,我们启动一个后台程序(比如定时任务),或者当有数据更新时,主动去更新缓存,这样做的好处是,缓存永远不会因为到期而失效,也就避免了因同时失效带来的雪崩风险,这就需要额外的逻辑来保证缓存数据和数据库数据的一致性。(来源:大型网站架构中常用的缓存策略)
  3. 构建高可用的Redis架构:单点的Redis服务一旦宕机,雪崩不可避免,所以生产环境一定要用高可用架构,最常见的就是主从复制+哨兵模式,简单说,就是准备多个Redis实例,一主多从,主节点负责写,从节点负责读和备份,哨兵进程负责监控主节点,一旦主节点挂了,它能自动从从节点中选举出一个新的主节点,继续提供服务,整个过程对应用程序几乎是透明的,从而保证了Redis服务本身的高可用性。(来源:Redis高可用性解决方案文档)
  4. 使用多级缓存:不要把所有鸡蛋放在一个篮子里,可以在应用本地(JVM内存)也放一份热点数据作为一级缓存,Redis作为二级缓存,这样即使Redis完全挂掉,本地缓存还能支撑一段时间,虽然数据可能不是最新的,但至少能保证核心页面可以打开,给修复Redis争取宝贵的时间。(来源:互联网公司应对超高流量的架构设计案例)

Redis雪崩的核心就是“大量缓存同时失效”导致数据库被压垮,应对的思路也无非是“防止它们同时失效”和“失效了也别让数据库死掉”,通过设置随机过期时间、构建高可用集群、做好限流降级等措施,完全可以避免这种灾难性的问题。

Redis雪崩到底是啥情况,缓存突然全挂了咋办啊