大家好,我是小米,31 岁,干 Java 这些年,最大的感悟就一句话:
系统不是用来“完美运行”的,而是用来“扛住事故”的。
今天我们来聊一个社招面试里高频但又特别容易答虚的题目:Redis 缓存降级。
很多同学一听到“缓存降级”,脑子里就只剩下一句话:Redis 挂了,就降级呗。然后就没然后了。
但如果你真这么答,面试官大概率会在心里默默记下一句: “只写过 Demo,没打过仗。”
先讲个故事:一座高速收费站的崩溃现场
想象一个场景。你在一条高速公路上,前方是一个超级大的收费站,平时通行顺畅。但某天节假日,车流量突然暴涨 10 倍。
收费站里有三类通道:
- ETC 通道:刷一下就走,最快
- 人工现金通道:慢一点
- 人工人工核对通道:查信息、对账、核验,最慢
这里我们来做一个类比:
正常情况下,90% 的车都走 ETC,高速又顺又稳。可某天,ETC 系统崩了。这时候如果你还坚持一个原则:“ETC 不能用,那所有车都去人工核对通道吧。”
那结果只有一个字:堵。 堵到天荒地老。
什么是缓存降级?一句话先说清楚
在正式展开前,先给一个面试级别的定义:
缓存降级,是指在访问量剧增、缓存服务异常或非核心服务影响核心链路时,系统主动或被动地放弃部分非核心功能,以“有损”的方式继续对外提供服务,从而保证核心服务可用。
注意这几个关键词:
- 有损
- 核心服务
- 主动 / 被动
- 不是 Redis 挂了才降级
为什么要做缓存降级?不是多此一举
很多刚工作一两年的同学会有个误区:Redis 挂了,我就查数据库呗。
这句话在低并发下是对的,在高并发下是灾难。我们来看一条典型的调用链:
正常情况
- 90% 命中 Redis
- 10% 访问数据库
- 数据库压力可控
Redis 出问题时(不降级)
- 100% 请求打到数据库
- 数据库连接池被打爆
- 线程阻塞
- 服务雪崩
Redis 挂了 → 数据库跟着挂 → 整个系统不可用。 这,就是经典的缓存雪崩升级版。
缓存降级的最终目的:一句话就够
保证核心服务可用,即使是有损的。
这句话在面试中非常重要,你可以直接背。而且要补一句:并不是所有服务都可以降级。
比如:
- 加入购物车 ❌
- 下单结算 ❌
- 支付 ❌
这些叫做:誓死保护的核心链路。
先梳理系统:丢卒,还是保帅?
在真正做降级之前,你要做的第一件事不是写代码,而是给系统做一次“战前分级”。
我一般会和团队一起画一张表。服务分级示意表如下所示:
一句话总结:能丢的,提前想好怎么丢;不能丢的,提前誓死保护。
缓存降级的触发方式:自动 vs 人工
你在面试中,一定要提这两种。
1、自动降级
适用于:
- 网络抖动
- Redis 偶发超时
- 成功率轻微波动
特点:
- 系统自动判断
- 不依赖人工介入
- 反应快
2、人工降级
适用于:
- 大促
- 已知风险
- 数据异常
- 紧急事故
特点:
- 可控
- 有开关
- 可随时恢复
用“日志级别”来类比降级策略(面试官很爱)
这是一个非常加分的说法。降级级别设计示例如下所示:
你可以这么总结给面试官听:我们把降级当成一种“运行态策略”,而不是异常处理。
最常见的缓存降级方式:直接返回默认值
现在来到最关键、最实战的部分。场景描述:
- Redis 不可用
- 这个缓存不是核心数据
- 不希望请求打到数据库
那怎么办?答案很简单:不查数据库,直接返回默认值。
Java 示例:Redis 降级实战代码
1、未降级前(有隐患)
问题在于:
- Redis 故障
- 所有请求直击数据库
2、加入缓存降级后的版本
3、默认值实现
这就是缓存降级的精髓: Redis 不行,我宁愿“给差一点的结果”,也不把数据库拖下水。
为什么不直接查数据库?再强调一次
因为:
- Redis 故障通常是高并发场景
- 数据库是最后一道防线
- 一旦数据库被拖死
- 核心链路全部完蛋
降级,是为了保护数据库。
总结成一段“面试标准答案”
如果面试官问你:
你怎么理解 Redis 缓存降级?
你可以这样答(建议背下来):
缓存降级的核心目标是保证系统核心服务可用,即使是有损服务。当访问量剧增、Redis 服务异常或非核心服务影响核心链路性能时,通过自动或人工降级策略,放弃部分非核心能力,避免请求直接打到数据库,从而防止缓存故障演变成数据库雪崩。常见做法是 Redis 不可用时直接返回默认值,而不是回源数据库。
END
做系统设计,一定要记住一句话:
系统不是为“正常情况”设计的,而是为“最糟糕的那一天”准备的。
缓存降级,就是你提前为那一天准备的逃生通道。
好朋友们,我们下篇见~
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!