项目用了 Redis 缓存来提升并发度,假设 Redis 挂了怎么办?
- 标签:后端、场景题
🏛 业务架构师
"Redis 挂了怎么办"我会分两个层次回答:怎么让它不容易挂(高可用架构),和真挂了业务怎么活(降级预案)。并先抛出一个架构师必问的问题:**你的 Redis 是缓存还是存储?**两者挂掉的严重度完全不同。
第一问:Redis 的角色定位
- 纯缓存(数据可从 DB 重建):挂了 = 性能降级,业务能活,预案是限流保护 DB
- 存储(session、订单号、分布式锁、计数器落在这里):挂了 = 功能受损甚至资损,这类数据必须重新评估归属——把存储型数据放进 Redis 又没持久化和容灾,是设计欠账
高可用分层(防挂)
- 主从 + 哨兵:秒级自动切换,解决单点
- Redis Cluster:分片 + 多副本,容量和吞吐水平扩展,单分片挂不影响全局
- 持久化:AOF everysec,主从数据延迟窗口 1 秒级——切换可能丢最近 1 秒写入,这对"计数器"无感,对"扣款流水"是灾难,再次论证存储类数据不该只放 Redis
真挂了的降级预案(保命)
- 本地缓存兜底:热点数据(配置、商品基础信息)Caffeine 多级缓存,Redis 挂了命中本地,扛住大部分读
- 限流回源:DB 前置限流(只放 20% 流量),宁可部分用户慢/排队,不能 DB 被打死造成全站瘫痪
- 功能降级开关:排行榜、猜你喜欢这类"锦上添花"功能直接关闭,保交易主链路
- 预案要演练:每次大促前做"杀 Redis"演练,没演练过的预案等于没有
收尾:我的验收标准一句话——Redis 全挂,核心交易可用性不降级到不可用。达不到,要么补架构,要么把关键数据挪出 Redis。
🏗 系统架构师
Redis 挂了怎么办——我分事前高可用架构与事中降级预案两层答,这也是考察架构完备性的题。
事前:Redis 本身就不该"一挂全挂"
- 主从 + 哨兵自动故障转移(10~30s 切换),或 Redis Cluster 多分片多副本,分片挂只影响 1/N 的 key
- 我的生产要求:客户端配
sentinel/cluster模式自动拓扑发现,应用无需重启 - 持久化开 AOF(everysec),极端场景重启数据丢失控制在 1s
事中:分级降级(Redis 不可用的几十秒里)
- 本地缓存兜底:多级缓存架构(Caffeine L1 + Redis L2)本来就是我的默认设计——配置数据、类目树这类读多写少的数据 L1 常驻,Redis 挂了 L1 继续扛大部分读
- 限流回源:Redis 失效瞬间所有读打向 DB,必须先熔断限流:网关/客户端对回源 QPS 设阈值(按 DB 承受力压测得出,如单机 2k),超出的请求快速失败或返回兜底内容,宁可部分降级不可打挂 DB
- 业务分级:核心交易链路(支付)直连 DB 强一致跑;非核心(推荐、计数)直接降级隐藏或用静态默认值
- Session/登录态:用 Redis 存 session 的系统要预案——短暂不可用期间放行已登录用户(JWT 本地校验免 Redis),或容忍临时登录失败
事后:恢复后防缓存雪崩式回源——缓存预热脚本渐进加载热点 key,而不是瞬时全量 miss。
一句话:Cluster 保高可用、多级缓存保读、限流保 DB、分级保业务,四个保署齐才敢说"Redis 挂了系统不挂"。
💻 全栈开发专家
先说架构:Redis 挂了不该是"灾难",而是"降级事件"。高可用 + 多级缓存 + 限流兜底三层。
1. 高可用(让"挂"变成秒级切换)
- 哨兵模式:主挂自动选从提升,10~30 秒恢复。
- Cluster 分片:容量与写入吞吐的扩展 + 主从自动切换。
- 跨机房:核心业务至少主从跨 AZ 部署。
2. 应用侧降级(切换期间的流量怎么办)
java
LoadingCache<String, Object> local = Caffeine.newBuilder()
.maximumSize(50_000)
.expireAfterWrite(5, TimeUnit.SECONDS) // 短 TTL,防脏数据太久
.build();
public Object get(String key) {
Object v = local.getIfPresent(key); // 1. 本地缓存
if (v != null) return v;
try {
v = redis.get(key);
if (v != null) { local.put(key, v); return v; }
} catch (Exception e) { /* 降级标记 */ }
try {
return dbQueryWithLimiter(key); // 3. DB 兜底 + 限流
} catch (RejectedExecutionException e) {
return DEFAULT_VALUE; // 4. 默认值/旧值
}
}回源 DB 必须套限流/熔断(Sentinel/Resilience4j),否则 Redis 挂掉瞬间全部流量打穿 DB,二次事故比 Redis 挂了还严重。
3. 坑
- 热点 key 在本地缓存里只存一份进程内副本,短 TTL 控制不一致窗口。
- 修复后回源风暴:Redis 恢复瞬间缓存全空,需要预热或灰度放量。