缓存雪崩是指大量缓存同一时间过期或Redis整体不可用,导致请求直击数据库引发级联故障;需通过多信号联合判定(如集群延迟>200ms且持续15秒、evicted_keys突增300%、DB连接池使用率>95%等≥3项)精准识别真雪崩,再按三级阶梯降级:一级启用本地缓存只读快照,二级关闭非核心字段组装,三级退化为字段级原子查询,并全程可观测、可回滚。

不能靠“缓存挂了就切数据库”这种粗放做法应对雪崩。真正有效的阶梯降级,依赖异常体系对故障类型做精准归因,再按严重程度分层触发不同强度的响应动作——不是所有雪崩都一样,也不是所有降级都该返回空。
异常体系必须能区分“真雪崩”和“假抖动”
雪崩不是简单地 Redis 响应变慢或个别 key 失效,而是有明确可观测特征的系统性坍塌。异常捕获层需联合多个信号实时判定:
- Redis 集群整体延迟 >200ms 且持续超 15 秒(非单节点抖动)
- evicted_keys 指标在 60 秒内突增 300% 以上(表明大量 key 批量失效或内存压爆)
- DB 连接池使用率连续 10 秒 >95%,且活跃事务数陡升(确认下游已承压)
- 同一前缀的 key(如 promo_202605_*)在分钟级窗口内 miss 率同步突破 90%
仅当上述 ≥3 项同时满足时,才标记为 CacheAvalancheException,进入阶梯降级流程;否则归为临时抖动,走熔断器半开探测,不触发降级。
三级降级开关绑定具体失败原因,不可泛化
降级不是统一返回默认值,而是按雪崩影响范围逐级收口,每级都对应明确的状态承诺和副作用边界:
- 一级(轻度雪崩):仅部分前缀 key 失效(如促销类),本地缓存启用“只读快照”——延长 TTL 至原值 3 倍,允许返回陈旧数据,但禁止任何写缓存操作
- 二级(中度雪崩):Redis 集群延迟超标 + evicted_keys 激增,自动关闭非核心字段组装(如跳过用户头像、商品视频等远程调用),接口仍返回结构完整 JSON,仅填充兜底文案或占位符
- 三级(重度雪崩):DB 连接池打满 + 事务堆积,强制切换为“字段级拆解降级”——聚合接口(如 getProductDetail)退化为多个原子查询,只查商品名称、价格、库存等强依赖字段,其余字段返回 null 并带 stale-while-revalidate 头,后台异步补全
自研二级缓存需内置可验证的降级契约
你的本地缓存组件不能只是个 Map,它得声明自己在什么异常下做什么、不做什么。例如:
- 在初始化时注册语义标签:[[on-failure: CacheAvalancheException → fallback-to: read-through-db, no-write]]
- 每次读取失败后,主动上报 cache_cause: avalanche 和 fallback_action: read_db_stale_allowed 到链路追踪
- 静态扫描工具可校验:若某方法标注了 [[fallback-to: redis]],则其 catch 块中不得出现 new RuntimeException(),必须 throw 包装后的受控异常
契约不是文档,是运行时可识别、可审计、可混沌注入验证的约束。
降级过程必须全程可观测、可回滚
每个降级动作都要生成带上下文的动作指令,而非只报“命中率下降”:
- APM 中为每个缓存操作打标:cache_result: miss_avalanche、fallback_level: 2、db_query_count: 1
- 监控看板实时展示:当前激活的降级级别、各接口降级调用量、降级后成功率变化曲线
- 所有降级写入操作(如 DB 查询)必须加 rollback-safe 标记,一旦 Redis 恢复,自动触发补偿任务将新数据同步回缓存,而非覆盖式刷新










