Skip to content

项目用了 Redis 缓存来提升并发度,假设 Redis 挂了怎么办? ​

  • 标签:后端、场景题

🏛 业务架构师 ​

"Redis 挂了怎么办"我会分两个层次回答:怎么让它不容易挂(高可用架构),和真挂了业务怎么活(降级预案)。并先抛出一个架构师必问的问题:**你的 Redis 是缓存还是存储?**两者挂掉的严重度完全不同。

第一问:Redis 的角色定位

  • 纯缓存(数据可从 DB 重建):挂了 = 性能降级,业务能活,预案是限流保护 DB
  • 存储(session、订单号、分布式锁、计数器落在这里):挂了 = 功能受损甚至资损,这类数据必须重新评估归属——把存储型数据放进 Redis 又没持久化和容灾,是设计欠账

高可用分层(防挂)

  • 主从 + 哨兵:秒级自动切换,解决单点
  • Redis Cluster:分片 + 多副本,容量和吞吐水平扩展,单分片挂不影响全局
  • 持久化:AOF everysec,主从数据延迟窗口 1 秒级——切换可能丢最近 1 秒写入,这对"计数器"无感,对"扣款流水"是灾难,再次论证存储类数据不该只放 Redis

真挂了的降级预案(保命)

  1. 本地缓存兜底:热点数据(配置、商品基础信息)Caffeine 多级缓存,Redis 挂了命中本地,扛住大部分读
  2. 限流回源:DB 前置限流(只放 20% 流量),宁可部分用户慢/排队,不能 DB 被打死造成全站瘫痪
  3. 功能降级开关:排行榜、猜你喜欢这类"锦上添花"功能直接关闭,保交易主链路
  4. 预案要演练:每次大促前做"杀 Redis"演练,没演练过的预案等于没有

收尾:我的验收标准一句话——Redis 全挂,核心交易可用性不降级到不可用。达不到,要么补架构,要么把关键数据挪出 Redis。

🏗 系统架构师 ​

Redis 挂了怎么办——我分事前高可用架构与事中降级预案两层答,这也是考察架构完备性的题。

事前:Redis 本身就不该"一挂全挂"

  • 主从 + 哨兵自动故障转移(10~30s 切换),或 Redis Cluster 多分片多副本,分片挂只影响 1/N 的 key
  • 我的生产要求:客户端配 sentinel/cluster 模式自动拓扑发现,应用无需重启
  • 持久化开 AOF(everysec),极端场景重启数据丢失控制在 1s

事中:分级降级(Redis 不可用的几十秒里)

  1. 本地缓存兜底:多级缓存架构(Caffeine L1 + Redis L2)本来就是我的默认设计——配置数据、类目树这类读多写少的数据 L1 常驻,Redis 挂了 L1 继续扛大部分读
  2. 限流回源:Redis 失效瞬间所有读打向 DB,必须先熔断限流:网关/客户端对回源 QPS 设阈值(按 DB 承受力压测得出,如单机 2k),超出的请求快速失败或返回兜底内容,宁可部分降级不可打挂 DB
  3. 业务分级:核心交易链路(支付)直连 DB 强一致跑;非核心(推荐、计数)直接降级隐藏或用静态默认值
  4. 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 恢复瞬间缓存全空,需要预热或灰度放量。