编程 Redis 命中率 98% 掉到 23%:穿透、击穿、雪崩是三种病,别用同一副药

2026-09-21 21:05:38

Redis 命中率 98% 掉到 23%:穿透、击穿、雪崩是三种病,别用同一副药

参考来源:阿里云开发者社区《命中率98%跌至23%,17条告警齐发:Redis缓存三大故障复盘》,另见 技术站转载

事故:618 促销凌晨,17 条告警齐发

  • Redis 命中率从 98% 断崖式跌到 23%
  • MySQL 连接池打满
  • 网关开始返 502
  • 每单支付慢 4 秒

根因不复杂:一批过期 key 的 TTL 被设成了同一秒,到点全部失效,几千个请求同一时刻打到数据库。这是典型的缓存雪崩。

很多团队出问题后第一反应是「加缓存」,但穿透、击穿、雪崩的成因和防御手段完全不同,用同一副药只会耽误排查。

三种病先分清

类型触发条件表现DB 压力防御排查特征
缓存穿透查不存在的 key永远不会命中持续高(无效查询)布隆过滤器 + 空值缓存请求分散,无热点 key
缓存击穿单个热点 key 过期瞬间命中瞬间归零再恢复瞬时打满分布式锁 + 逻辑过期某个 key 请求量异常集中
缓存雪崩大量 key 同时过期命中率断崖下降瞬间洪峰TTL 随机化 + 多级缓存 + 降级大量 key 同时 miss

穿透

布隆过滤器:二进制位数组 + 多个哈希函数。查询时只要有一位是 0,就一定不存在;说存在的小概率不存在(误判可控,但不漏判)。

空值缓存:把 null 也缓存,TTL 设 60–120 秒。太长有新数据仍返回旧 null,太短防不住高频攻击。

踩坑记录:误判率一开始设 0.001,内存占了几百兆;改成 0.01(1%,缓存场景完全够)后内存降了一个数量级。业内推荐 0.1%–5%,只有安全敏感场景才追求更低。

落地用 RedisBloom 模块:

docker run -d --name redis-bloom -p 6379:6379 redislabs/redismod:latest

手动挂载:

git clone https://github.com/RedisBloom/RedisBloom.git && cd RedisBloom && make
docker run -d --name redis-bloom -v /opt/redis/modules:/modules redis:7-alpine --loadmodule /modules/redisbloom.so

验证模块是否加载(应看到 bf):

docker exec -it redis-bloom redis-cli MODULE LIST
BF.RESERVE user_ids_filter 0.01 1000000
BF.ADD user_ids_filter "user_123"
BF.EXISTS user_ids_filter "user_123"   # 1

注意两件事:过滤器初始化后大小不可改;数据删除频繁的场景可以换布谷鸟过滤器,它支持删除。

击穿

互斥锁(Mutex):适合强一致场景。别手写 SETNX,线程异常退出锁不释放,其他线程会一直等。生产用 Redisson,有看门狗机制,线程异常退出会自动释放。

逻辑过期:适合响应时间要求 200ms 以内、不能等待的场景。value 里自带过期时间字段,Redis 的 TTL 设很长;查询时判断逻辑过期时间,过期就让后台线程异步重建,其他线程先返回旧值。

雪崩

  • TTL 随机化:基础 TTL + 随机偏移,偏移量取基础值的 5%–10%,例如 3600s 加 300s 随机。偏移别超 10%,否则会拉长数据一致性窗口。
  • 多级缓存:本地缓存 + Redis。
  • 资源隔离与熔断降级:Sentinel / Resilience4j。
  • 持久化:Redis 宕机是更致命的雪崩诱因,配置 AOF + RDB,防止重启后缓存为空再引发一次雪崩。
  • 限流:单接口 QPS 超阈值直接返回 429。

排查与监控

雪崩场景下别用 KEYS 排查。生产环境执行 KEYS 会让 Redis 阻塞十几秒,用 SCAN 代替。

监控上,命中率低于 80% 就要开始排查穿透;数据库连接池要设最大连接数上限。

回头看这次事故,17 条告警、502、支付慢 4 秒,源头只是一批 TTL 写成了同一个值。

复制全文 生成海报 Redis 缓存 高并发 布隆过滤器

推荐文章

程序员茄子在线接单