1大促值班夜:三条告警被当成同一种「缓存雪崩」
某电商大促前一周,缓存团队收到三条告警:MySQL 连接数飙到上限、Redis 内存使用率瞬间归零、 接口 P99 从 50ms 涨到 3s。值班同学第一反应是「缓存雪崩了」,于是紧急给全量 Key 加随机 TTL、 扩容 Redis 节点——结果第二天凌晨,某个爆款 SKU 的详情页依然把数据库打满。
复盘才发现三条根因链并行存在:
- 09:12 穿透:80% 查询为不存在的负数商品 ID,Redis miss 率 99%,DB 返回空。
- 09:35 基础设施级雪崩:运维在预发误执行
FLUSHALL,但 DNS 指向了生产集群,全量 Key 消失。 - 10:00 击穿:爆款 SKU 8888 的 Key 整点过期,约 5000 QPS 同时 miss,DB 单 Key 排队。
若只执行「全量 TTL 加随机」和「扩容 Redis」,只能缓解第三条的部分复发概率,对穿透和误操作毫无作用。
以上为复合场景,用于说明真实生产中「缓存故障」标签下的根因往往不止一种。 值班群里常见另一种误判:把 MySQL 慢查询增多一律归因于「缓存没写好」,实际上可能是索引缺失、 连接池配置过小,与缓存无关。因此本文强调先分类、再处置——用监控指标把问题锁进 击穿 / 雪崩 / 穿透 / 非缓存四类之一,再打开对应的工具箱。 若值班同学只执行「全量 TTL 加随机」和「扩容 Redis」,只能缓解击穿的部分复发概率, 对穿透和误操作雪崩毫无作用——这就是为什么需要识别框架优先于处置动作。
基于 Redis 7.x,面向已有基础缓存用法的同学,聚焦五件事:三类经典问题如何识别与防护、 多级缓存怎么分层才不脏读、大 Key/热 Key 如何治理、主从 / Sentinel / Cluster 怎么选型、 以及可交接的防护 SOP。机制描述区分已核验事实(Redis 官方文档可查证)与 作者经验总结(如单机内存规划阈值),后者需结合本团队压测数据校准。
识别框架:三个判定问题
接到「缓存相关故障」告警后,按顺序问三个问题:
- Key 是否存在? 若大量请求查询的 Key 在 DB 中也不存在,偏向穿透。
- 失效是局部的还是批量的? 单个或少数热点 Key 同时过期/缺失,偏向击穿;大面积 Key 在同一时间窗口失效或 Redis 整体不可用,偏向雪崩。
- Redis 本身是否健康? 若集群宕机、网络分区或大规模驱逐,属于基础设施层雪崩,与应用层 TTL 策略是不同处置路径。
| 维度 | 缓存击穿 | 缓存雪崩 | 缓存穿透 |
|---|---|---|---|
| 触发条件 | 热点 Key 过期或被逐出,并发回源 | 大量 Key 同时过期,或 Redis 整体故障 | 查询不存在的数据,缓存与 DB 均 miss |
| 影响范围 | 通常集中在少数热点 | 全站或某业务域大面积 | 取决于攻击/异常流量规模 |
| 典型监控信号 | 单 Key QPS 尖峰 + DB 慢查询关联该 Key | Redis hit rate 断崖 + DB 连接池耗尽 | miss 率异常高但 DB 返回空结果比例高 |
| 首选防护 | 互斥锁 / 逻辑过期 / 永不过期+异步刷新 | TTL 随机化 / 集群 HA / 限流降级 | 布隆过滤器 / 空值短 TTL / 参数校验 |
「给所有 Key 加互斥锁」无法解决穿透——不存在的数据永远不会被锁保护后的重建逻辑写入缓存。
反过来,「全站加随机 TTL」对单个热点 Key 的击穿帮助有限。还有团队把「缓存雪崩」与「Redis 集群脑裂」混谈:
后者是 HA 层问题,解法在 Sentinel quorum 与 min-replicas-to-write,而不是 TTL 随机化。
正确做法是先分类,再组合防护,而不是选一个「万能方案」。
监控指标与告警阈值(经验参考)
- 缓存命中率:按业务域分桶。单域 5 分钟内下降超过 20 个百分点,且 DB QPS 同比上升,触发雪崩或大面积失效排查。
- 单 Key QPS:某 Key 的 miss 后 DB 查询在 1 秒内超过 500 次(阈值因业务而异),优先怀疑击穿。
- 空结果比例:回源 DB 后返回空行的请求占比持续高于基线 3 倍,优先怀疑穿透或布隆失效。
- Redis 可用性:Sentinel 的 master-switch、Cluster 的 failover 应接入告警,与 hit rate 断崖关联分析。
分类不能靠猜,需要指标支撑。建议在 APM 或 Prometheus 中维护上述观测项,并把「变更单 / 发布窗口 / ACL 审计」
作为第四类信号源——复合场景里的 FLUSHALL 往往先出现在变更系统,而不是应用日志。
值班手册若只覆盖单一故障模型,几乎必然在促销窗口踩坑:处置动作互相打架,复盘时才发现三条根因链并行。
从现场反推架构缺口时,建议固定用「现象 → 机制 → 参数」三层提问:例如「DB 连接打满」→ 「是空结果穿透、热点 miss 还是 Redis 不可用」→「布隆是否失效、互斥是否缺失、ACL 是否过宽」。 避免直接跳到「加机器 / 加随机 TTL」而跳过机制层。本文后半部分的 SOP 与决策矩阵, 就是把这套提问顺序写成可交接的值班动作。
后文按「总览 → 多级一致性 → 三类防护 → 大 Key/热 Key → 集群 → 适合/不适合 → SOP → 决策矩阵」展开。 参数默认值与命令行为以 Redis 7.x 官方文档为准;容量与阈值属于待压测校准的经验推断。
2缓存防护四层栈:识别、分层、治理、高可用
在进入互斥锁与布隆过滤器细节之前,先建立一张概念地图:分布式缓存的「高阶实战」不是单一补丁, 而是四层叠加。任意一层缺失,都会在促销窗口以 DB 打满、脏读或单分片打爆的形式暴露出来。
值班时最浪费时间的模式,是把三类不同问题揉成一个口号「缓存又挂了」。 第 1 章的识别框架与第 9 章的决策矩阵,分别对应「事中快速归层」与「事后选型收束」。 读后文时建议始终带着一张「责任归属表」:命中率与空结果比是应用观测责任; Redis 进程存活与 failover 是平台责任;大 Key / 热 Key 往往是数据模型与 Key 设计责任。 三方互相指认「缓存又出问题」却不先回答「问题落在哪一层」,会把 15 分钟止血窗口耗在扯皮上。
另需澄清一个常见措辞:口语里的「上了 Redis 就高可用」往往混用了三种含义—— 单实例进程存活、主从/Sentinel 自动切换、Cluster 分片扩展。本文刻意拆开讲述, 是为了避免在架构评审里用一个营销词覆盖三类完全不同的工程控制点。 同样,「加了缓存就一定更快」也要拆开:L1 降低网络 RT,L2 降低 DB 压力, 但若 Value 过大或序列化过重,缓存层本身可能成为新的 P99 瓶颈。
3本地缓存 + Redis:读路径回填与写路径失效
单一 Redis 层在 QPS 极高或网络 RT 敏感的场景下容易成为瓶颈。多级缓存的标准模型是: L1 进程内本地缓存(Caffeine、Guava Cache 等)+ L2 分布式 Redis + L3 数据库。设计目标是在命中率、一致性和运维复杂度之间取平衡,而非盲目堆层数。
写策略选择
- Cache-Aside(旁路缓存):应用先写 DB,再删缓存(或删 L1+L2)。最通用,适合多数业务。
- Read-Through / Write-Through:缓存组件封装读写,适合统一缓存 SDK 的团队。
- Write-Behind:先写缓存异步刷 DB,吞吐高但丢数据风险大,仅适合可容忍短暂不一致的统计类场景。
L1 失效可用 Redis Pub/Sub 快速广播,或用 Redis Streams 做至少一次投递。
Pub/Sub 不持久化,实例重启期间可能丢消息,需配合 L1 短 TTL。
Redis 7 的 CLIENT TRACKING(服务端辅助缓存)可在客户端缓存与 Redis 之间建立 invalidation 通道,
需客户端库支持 RESP3(Lettuce 6.3+ 可开启)。
Redis Pub/Sub 是 fire-and-forget:离线订阅者不会收到历史消息;官方文档明确其不提供持久化投递保证。 因此「仅靠 Pub/Sub 保证 L1 强一致」在机制上不成立,必须叠加短 TTL、Streams 或 CLIENT TRACKING。
// Cache-Aside 读路径示意(Spring + Caffeine + Redis 7.x)
public Product getProduct(Long id) {
String key = "product:" + id;
Product p = localCache.getIfPresent(key);
if (p != null) return p;
String json = redisTemplate.opsForValue().get(key);
if (json != null) {
p = parse(json);
localCache.put(key, p);
return p;
}
return loadFromDbWithMutex(key, id); // 见第 4 章
}
本地缓存适合读多写少、可容忍秒级不一致的配置类、字典类、商品基础属性。 订单状态、库存余额等强一致数据不应长时间停留在 L1,或 L1 TTL 控制在亚秒级并配合主动失效。 若团队尚无统一缓存 SDK,优先落地 L2 Redis + 规范 Cache-Aside,再逐步引入 L1。
容量与命中率估算
设计多级缓存前先估算 L1 命中率目标。若单实例 QPS 为 5000,L1 命中率 60%,则打到 Redis 的 QPS 为 2000;
L1+L2 综合命中率 95%,则 DB 回源仅 250 QPS。L1 的 maximumSize 按「热点 Key 数量 × 单对象大小」估算,
避免 OOM;Caffeine 默认基于 Window TinyLFU 驱逐冷数据,比纯 LRU 更适合热点漂移场景。
热点数据可配置单飞(singleflight):同一 JVM 内合并对同一 Key 的并发回源,
与 Redis 层的分布式锁形成互补——L1 防重复构造对象,L2 防重复打 DB。
一致性窗口要写进架构评审材料:Cache-Aside「先写 DB 再删缓存」在并发下仍可能出现极短脏读窗口 (读线程在删除前把旧值写回)。业界常见补救是延迟双删、订阅 binlog 失效,或接受秒级不一致。 评审时不要承诺「绝对一致」,而要写清:用户可见不一致窗口上限、是否可对账补偿、哪些字段禁止进缓存。
4穿透、击穿、雪崩:识别决策流与防护组合
以下方案按问题类型组织,生产环境通常组合使用。验证层通过方案对比矩阵评估 trade-off, 避免「只上布隆过滤器」或「只加锁」的片面治理。
缓存击穿防护
互斥锁(Mutex):Key miss 时,仅一个线程回源 DB 并写回 Redis,其余线程等待或短暂重试读缓存。
Redis 7 可用 SET key value NX EX ttl 实现简易分布式锁;更严谨场景用 Redisson RLock
并设置 lock 等待超时,防止死等。
逻辑过期:Value 携带逻辑过期时间,物理 Key 不设 TTL(或极长 TTL);后台异步刷新,前台仍返回旧值。 适合「绝对不能 miss」的页面渲染数据。库存、余额等不能用逻辑过期返回旧值,除非业务明确接受风险。
# Redis 7.x:互斥重建示意
SET lock:product:10086 "1" NX EX 10
# 获锁成功才回源 DB,再 SET product + DEL lock
缓存雪崩防护
TTL 随机化:在基础过期时间上叠加秒级抖动,避免整批 Key 在同一秒失效。
多级缓存 + 限流:Redis 不可用时 L1 可扛部分读;网关 Sentinel / 令牌桶限制回源 QPS。
集群高可用:应用层雪崩与 Redis 宕机雪崩要分开预案;配置合理的
maxmemory-policy(通常 allkeys-lru 或 volatile-lru)。
缓存穿透防护
空值缓存:DB 查不到时写入短 TTL 空标记(30~120 秒)。
布隆过滤器:RedisBloom 模块(BF.ADD / BF.EXISTS)或应用侧 Guava;
有误判、不易删除,适合 ID 集合相对稳定的场景。
接口层校验:对 ID 格式、范围做前置校验,成本最低,应作为第一道防线。
| 方案 | 主要应对 | 优点 | 代价 / 风险 |
|---|---|---|---|
| 互斥锁 | 击穿 | 严格限制回源并发 | 锁竞争增加延迟;超时需调参 |
| 逻辑过期 + 异步刷新 | 击穿 | 热点零 miss 窗口 | 短暂脏读;需刷新线程池 |
| TTL 随机化 | 雪崩 | 零侵入 | 无法应对 Redis 整体宕机 |
| 空值短 TTL | 穿透 | 实现成本极低 | 非法 Key 极多时仍占内存 |
| 布隆过滤器 | 穿透 | 内存小、拦截高效 | 有误判;难删除;需预热 |
| 限流降级 | 雪崩兜底 | 保护 DB 最后防线 | 影响体验,需产品认可 |
互斥锁未设最大等待时间时,Redis 短暂抖动会导致大量线程阻塞在锁上,线程池耗尽比 DB 被打满更难恢复。 布隆过滤器未随数据增长扩容时,误判率上升。还有团队用预热脚本把全部 Key 写成同一时刻过期——这本身就是雪崩种子。 大促前务必做热点预载 + 逻辑过期 + 限流组合演练。
互斥重建完整流程要点
生产落地时建议「双重检查 + 有界等待」:获锁前再读一次缓存;获锁后再次读缓存,避免惊群后重复回源;
未获锁则短自旋(例如 5 次 × 50ms)读缓存,超时后降级直读 DB 并必须配合限流。
空结果路径写入短 TTL 的 NULL 占位,把穿透防护嵌进同一回源函数,避免两套逻辑分叉。
逻辑过期则在 Value 中嵌入 expireAt,物理 Key 不设或极长 TTL;读到逻辑过期时返回旧值并异步刷新——
该模式适合页面渲染,不适合资金类。
// 分布式锁 + 双重检查要点(Redis 7.x)
boolean locked = setIfAbsent("lock:"+key, "1", Duration.ofSeconds(10));
if (locked) {
try {
Product p = tryGetFromRedis(key);
if (p != null) return p;
p = productDao.findById(id);
if (p != null) set(key, p, Duration.ofHours(1));
else set(key, "NULL", Duration.ofSeconds(60)); // 穿透
return p;
} finally { del("lock:"+key); }
}
// 未获锁:有界自旋后降级,配合限流
方案组合推荐按业务类型取舍:商品详情偏逻辑过期 + 热点预载;用户资料偏布隆 + 空值; 库存余额偏短 TTL Cache-Aside 且慎用 L1;配置字典偏 L1 + Redis + 失效广播。 验证层用上表对比矩阵评估 trade-off,而不是追求「一套方案打天下」。
5大 Key 与热 Key:为何单分片会先于「雪崩」倒下
许多团队把 Cluster 某节点 CPU 100% 误诊为「雪崩」,实际上是热 Key把流量打进同一 hash slot, 或大 Key在序列化、删除、迁移时阻塞事件循环。二者与穿透/击穿/雪崩相关,但处置工具箱不同。
大 Key 治理要点
- 用
MEMORY USAGE与定期扫描发现大 Key;避免生产长时间KEYS。 - 删除用
UNLINK(异步)替代阻塞DEL;Hash/Set 过大时分片为多个子 Key。 - 禁止对超大集合执行
HGETALL/SMEMBERS,改用游标扫描(HSCAN)。 - Cluster 迁移时大 Key 会拉长迁移窗口,单节点有效数据建议控制在可接受 failover 时延内(作者经验常谈 10~20GB 量级,需压测)。
热 Key 治理要点
- 大促前从访问日志提取 Top N,预载并配置逻辑过期或更长 TTL。
- L1 本地缓存 + singleflight 合并 JVM 内并发回源,与 Redis 层互斥锁互补。
- 必要时做「热 Key 副本」:多 Key 随机后缀读写时选一个,牺牲一点一致性换吞吐(仅适合可接受短暂不一致的读多场景)。
- Cluster 下注意 hash tag:
{user}:1000与{user}:profile同 slot,便于多 Key 操作,也可能把热点捆死在同一分片。
看见 Cluster 某分片 CPU 高就「整体扩容」——若根因是单 Key 热点,加节点不会把已有 Key 的流量打散,
除非做 Key 重设计或本地缓存分流。大 Key 上直接 DEL 可能造成比业务峰值更严重的阻塞尖刺。
与三类经典问题的交叉关系
热 Key 过期会表现为击穿;大 Key 被驱逐或迁移失败可能放大为局部雪崩;恶意扫描大范围不存在 ID 是穿透, 但若攻击者同时打爆某个存在的爆款 Key,现场会同时出现穿透与击穿信号。因此 SOP 要求并行看 「空结果比」与「单 Key QPS」,而不是二选一。治理优先级上:先止血(限流 / 延长 TTL / 封禁), 再结构性修复(拆 Key / 改 hash tag / 补布隆),最后才是扩容。跳过结构修复直接扩容, 成本上升而根因仍在——这是促销复盘里最高频的无效投入。
探测工具要分环境使用:生产短时 MONITOR 风险极高,优先用采样埋点与慢日志;
压测与预发可用 redis-cli --hotkeys 与 MEMORY USAGE 做基线。
把「大 Key 清单」和「热 Key 清单」纳入发布门禁:新接口若写入无界增长的集合(如按天追加的 List),
必须在设计评审阶段给出拆分策略,而不是上线后再被动扫描。
6主从、Sentinel 与 Cluster:适用边界与拓扑
缓存防护方案再完善,Redis 单点宕机仍会触发「基础设施级雪崩」。Redis 7.x 三种主流部署模式适用边界如下。
| 模式 | 高可用 | 水平扩展 | 运维复杂度 | 典型适用 |
|---|---|---|---|---|
| 主从 | 手动切换 | 只读扩展 | 低 | 测试、可停机 |
| Sentinel | 自动故障转移 | 单机垂直扩展 | 中 | 中小规模生产 |
| Cluster | 分片 + Replica | 数据与写 QPS 分片 | 高 | 大数据量、高写、可接受 slot 约束 |
Redis 7 支持多部分 AOF(base + 增量),降低重写期间磁盘压力;缓存层若开启 AOF,需评估
appendfsync everysec 对 P99 的影响。生产建议启用 ACL 最小权限,禁止应用使用
FLUSHALL、CONFIG 等高危命令——复合场景中的误操作雪崩,往往能被 ACL 直接阻断。
Redis Cluster 将键空间划分为 16384 个 hash slot;多 Key 操作要求 Key 落在同一 slot(可用 hash tag)。 跨 slot 的事务与部分多 Key 命令不可用。客户端必须能处理 MOVED/ASK 重定向。
主从、Sentinel、Cluster 的机制要点
主从复制:一个 Master 负责读写,Replica 异步复制。无 Sentinel 时默认不会自动故障转移,
Master 宕机需人工提升或外部工具。关键参数 repl-backlog-size 影响断线重连后的增量同步;
全量同步期间 RDB 生成会消耗 CPU 与 IO,大内存实例需评估。
Sentinel:至少 3 个 Sentinel 监控主从,主观下线后选举新 Master 并通知客户端。
适用于数据量可单机承载、需要自动 HA、不需要水平分片的大多数生产业务。
客户端应使用 Sentinel 感知的连接工厂,避免硬编码 Master IP;配置
min-replicas-to-write 有助于降低脑裂时写入孤立 Master 的风险。
Cluster:16384 个 hash slot 分布到多 Master,每个 Master 可挂 Replica。
生产应为每个 Master 配置至少一个 Replica,并保证主从不在同一机架。
客户端务必开启拓扑自动刷新(如 Lettuce ClusterTopologyRefreshOptions),
在 slot 迁移或 failover 后及时更新映射,避免大量 MOVED 导致延迟尖刺。
# Redis 7.x 运维常用诊断
redis-cli INFO replication
redis-cli INFO memory
redis-cli CLUSTER NODES
redis-cli CLUSTER SLOTS
托管与自建的取舍:自建可控、无厂商绑定,但需专职巡检与升级;云托管提供备份与一键扩容, 但可能限制部分命令并产生跨可用区流量成本。核心选型逻辑不变——先回答数据量与 HA 需求,再选交付形态。
7什么场景该押注 Redis 缓存栈,什么时候别硬上
适合继续用 Redis 做分布式缓存
- 读多写少、可接受最终一致或秒级不一致的读路径加速
- 热点相对稳定或可预载,防护组合可落地(互斥/布隆/TTL 抖动)
- 数据量与写 QPS 落在 Sentinel 或 Cluster 可运维边界内
- 已有统一 Cache-Aside 规范与监控(命中率、空结果比、单 Key QPS)
不适合硬上或应降级方案
- 强一致库存/资金以缓存为唯一真相源(应直写 DB/专用库存服务)
- 超大 Value、复杂多键事务却不愿做 hash tag 重设计
- 把 Redis 当消息队列或无限期主存储(缺少淘汰与持久化策略)
- 团队无人会做 failover 演练与大 Key 巡检,却上复杂 Cluster 多活
| 业务类型 | 推荐组合 | 说明 |
|---|---|---|
| 商品详情 / 内容页 | 逻辑过期 + 热点预载 + 互斥锁 | 可容忍秒级旧数据 |
| 用户资料 / 搜索联想 | 布隆 + 空值 TTL + TTL 随机化 | 非法 ID 多 |
| 库存 / 账户余额 | 短 TTL Cache-Aside + 限流,慎用 L1 | 强一致优先 |
| 配置 / 字典 | L1 + Redis + Pub/Sub 失效 | 读极多写极少 |
定量门槛(需压测校准):有效数据内存持续大于约 50GB 或写 QPS 逼近单主上限时评估 Cluster; 多数微服务缓存场景 Sentinel + 主从即可。跨机房多活若读异地 Replica,注意复制延迟导致的读不一致, 强一致读必须走 Master 或本地缓存失效链。
何时该「少用缓存」
不是所有读都能靠缓存变快。写入占比高、Value 极大、一致性窗口极短、或访问长尾极度均匀(几乎没有热点)时, 缓存命中率上不去,却要承担序列化、内存与一致性治理成本。此时更合理的路径是:优化 DB 索引与查询、 读写分离、CQRS 读模型,或把热点抽成独立服务,而不是继续加厚 Redis 层。 架构评审里应显式回答三个问题:命中率目标是多少?不一致可接受多久?谁负责大 Key/热 Key 巡检? 答不上来却坚持「全面缓存化」,通常会在第一个大促窗口暴露为 DB 与 Redis 双重过载。
适合与不适合的边界也会随组织能力移动:同一套 Cluster 拓扑,在有专职 SRE 与季度演练的团队是资产, 在无人会做 failover 的团队是负债。决策矩阵下一章会把「继续 / 迁移 / 选型」写成可打勾的评审表, 避免口头争论「要不要上 Cluster」却不对照信号。
8缓存故障防护 SOP 与大促检查表
面向值班与架构评审的标准处置流程。现象出现后,先走第 1 章识别框架分类,再执行对应列。
| 故障现象 | 排查工具 / 命令 | 根因定位要点 | 处置方案 | 预防机制 |
|---|---|---|---|---|
| 单接口 DB QPS 突增,miss 集中个别 Key | SLOWLOG、APM 热点 Key、--hotkeys |
Key 是否刚过期或被 LRU 驱逐 | 回源限流;延长热点 TTL;启用互斥重建 | 逻辑过期 + 热点预载;singleflight |
| 全站 hit rate 骤降,DB 连接池告警 | INFO stats、INFO memory、存活监控 |
区分宕机 / 驱逐 / 批量 TTL / 误操作 | 切新 Master;网关限流;L1 延长兜底 | TTL 随机化;HA;ACL 禁 FLUSHALL |
| miss 高但 DB 空结果占比高 | 访问日志、WAF、布隆命中率 | 恶意扫描 ID 或缺参数校验 | 空值缓存;布隆;封禁异常流量 | 接口校验;布隆预热;空值短 TTL |
| 主从切换后短暂脏读 | INFO replication、Sentinel 日志 |
客户端是否缓存旧 Master | 重启连接池;确认新 Master | Sentinel 客户端;切换演练 |
| Cluster 某分片 CPU 100% | CLUSTER NODES、SLOWLOG |
hot slot / 大 Key / 热 Key | 拆分大 Key;本地缓存分流;重设计 hash tag | Key 评审;定期 slot 均衡 |
| L1 与 Redis 不一致客诉 | 对比 DB / Redis / 各实例 L1 | 失效广播丢失或写路径漏删 | 缩短 L1 TTL;补发失效;修写路径 | Pub/Sub 改 Streams;写路径评审 |
大促前缓存防护检查要点
- 热点 Key 清单是否已从上次大促日志提取并预载?逻辑过期或加长 TTL 是否已生效?
- 批量导入任务的 TTL 是否加了随机偏移,避免整批同一秒失效?
- 布隆过滤器是否已同步最新商品 ID 集合,误判率是否仍在可接受区间?
- Sentinel / Cluster failover 演练是否在 30 天内执行过,客户端是否自动感知新主?
- 缓存 miss 后是否有限流规则兜底(可联动 Sentinel 流量防护体系)?
- ACL 是否已禁止应用账号执行
FLUSHALL/KEYS/ 危险CONFIG? - 大 Key 扫描与 Top 热 Key 报告是否已归档,分片倾斜是否有预案?
- L1 失效广播通道是否健康,短 TTL 兜底是否仍开启?
故障演练建议节奏
每季度至少一次:模拟热点 Key 过期(压测环境批量 DEL)、模拟 Sentinel failover
(SENTINEL failover)、模拟穿透流量(随机非法 ID 压测)。演练后更新 SOP 与告警阈值。
Redis 7.x 的 redis-benchmark 可用于基准 QPS,但 miss 路径与 hit 路径差异巨大,
必须以业务真实 payload 压测为准。演练记录建议至少包含:触发方式、观察到的指标曲线、
实际执行的处置步骤、是否误伤正常流量、以及预防机制是否需要改 Wiki。
没有记录的演练等于没有演练——下一次大促仍会重复同一套口头经验。
与相邻体系的联调也很关键:缓存 miss 限流规则应在网关或 Sentinel 控制台可一键开启; 热点名单与 TTL 参数若走配置中心,需验证推送失败时的默认值是否安全(失败开放还是失败关闭)。 这些联调项不属于 Redis 进程本身,却决定「防护 SOP」在真实流量下能不能跑通。
复合场景值班夜最有效的节奏是:T+0 确认 Redis 存活;T+3 看空结果比与单 Key miss; T+8 决定是开限流、补布隆还是延长热点 TTL;T+15 再查变更单与 ACL 审计。 顺序反了——例如先全量改 TTL——会浪费窗口且掩盖穿透。
9决策矩阵:继续加固、迁移 Cluster 还是降级语义
当评审卡在「要不要上 Cluster」「要不要加 L1」「要不要逻辑过期」时,用下面的决策矩阵收束讨论。 列含义:继续(当前架构加固)、迁移(换部署形态或写路径)、选型(在防护手段间取舍)。
| 场景信号 | 继续(加固) | 迁移 / 升级 | 选型注意 |
|---|---|---|---|
| 偶发热点击穿,单机内存充足 | 互斥 + 逻辑过期 + 预载 | 暂不需要 Cluster | 库存类勿用逻辑过期脏读 |
| 有效数据持续 > 50GB 或写逼近单主上限 | 垂直扩容评估成本 | 评估 Redis Cluster | 先做 hash tag 与多 Key 审计 |
| 非法 ID / 爬虫穿透 | 校验 + 空值 + 布隆 | 不必因穿透上 Cluster | 布隆需预热与扩容计划 |
| 需要进程内极低延迟读 | L1 + 短 TTL / Streams 失效 | 统一缓存 SDK 后再规模化 | 强一致字段慎放 L1 |
| 单分片 CPU 打满且 Top Key 明确 | 本地缓存分流 / 热 Key 副本 | 盲目加节点往往无效 | 先治理 Key,再谈扩容 |
| 误操作 FLUSHALL / 高危命令 | ACL + 变更双人复核 | 托管 Redis 可降低运维面 | TTL 随机化防不住误操作 |
| 团队无 HA 演练能力 | 先跑通 Sentinel 演练 | 暂缓复杂多活 Cluster | 复杂度超过收益则降级 |
集群选型定量门槛(经验,需压测校准)
| 指标 | Sentinel + 主从通常足够 | 建议评估 Cluster |
|---|---|---|
| 有效数据内存 | < 50 GB | > 50 GB 且垂直扩容成本高 |
| 写 QPS(单主) | < 8~10 万(视 value 大小) | 持续逼近单核网络/CPU 上限 |
| Key 总数 | < 5000 万(视内存) | 单实例 RDB/AOF 重写时间过长 |
| 多 Key 事务需求 | 无跨 Key 原子要求 | 需 hash tag 重设计,评估复杂度 |
以上为经验区间,非 Redis 官方硬限制。实际应以 failover 耗时、AOF 重写时长、P99 延迟三类 SLO 反推架构, 而非只看数据量绝对值。评审会上若有人只甩「我们已经 60GB 了所以必须 Cluster」, 应追问:60GB 是有效数据还是含碎片与副本?单次全量同步要多久?多 Key 事务是否已盘点? 把决策从口号拉回可验证的 SLO,才能避免过度设计或欠设计。
相邻知识地图
- T12 Sentinel 流量防护:缓存失效时的限流/熔断兜底,与雪崩防护最后一道闸门联动。
- T11 Nacos 配置中心:缓存 TTL、布隆开关、热点名单可动态下发,避免发版改参。
- T19 Kafka 高可靠:写路径先落 Kafka,消费者异步更新 DB 并失效缓存,降低双写耦合。
沉淀要点
- 击穿、雪崩、穿透的识别顺序:Key 是否存在 → 失效范围 → Redis 是否健康;三者解法不同。
- 多级缓存的核心矛盾是一致性:L1 必须配失效广播或极短 TTL,写路径以 Cache-Aside 删缓存为主流。
- 防护组合:穿透(校验 + 布隆 + 空值)、击穿(互斥 / 逻辑过期)、雪崩(TTL 抖动 + HA + 限流)。
- 大 Key / 热 Key 是独立治理面:拆分、UNLINK、本地分流,盲目扩容 Cluster 往往无效。
- 集群选型默认 Sentinel + 主从;数据量或写 QPS 超单机边界再上 Cluster。
团队落地建议:将「识别决策流」和「集群选型口诀」做成值班区速查卡;将 SOP 表格导入 Wiki, 每季度演练后更新「预防机制」列。Redis 版本升级(6.x → 7.x)时重点回归 ACL、多部分 AOF 与客户端 RESP3 兼容性, 避免升级窗口引发非预期雪崩。大促前必做:热点 Key 清单、逻辑过期配置、故障切换演练与 SOP 走查—— 这些动作比临时改 TTL 更能降低复合故障复发率。
本篇是配套中间件系列收官视角下的缓存治理框架:它不替代官方文档中的命令细节, 而是把「分类 → 分层 → 防护 → Key 治理 → 部署选型」串成可执行链路。 读完后应能独立画出防护 SOP 与集群选型决策路径,并在压测或故障演练中验证方案有效性。 若只能带走一句话:先分清打的是哪一类问题,再打开对应工具箱——叠补丁解决不了分类错误。 分类对了,互斥、布隆、TTL 抖动与 Cluster 才会各自回到正确的位置; 分类错了,再多补丁也只是在错误图层上加班。