Redis 热点 key 过期后数据库被打满:缓存击穿怎么排查和修复
不少 Redis 故障表面看是数据库响应变慢,实则根因出在缓存层突然失守。比如商品详情页的 product:1001 是热点 key,平时 Redis 命中率维持在很高水平,数据库负载一直很平稳;一旦某个时间点这个 key 刚好过期,大量同时涌来的请求直接没命中缓存,全量打到后端数据库。最终出现接口响应拖慢、DB QPS 瞬间冲高、Redis 命中率断崖式下跌,这就是非常典型的缓存击穿现场。
要点速览
- 缓存击穿通常发生在单个热点 key 过期的一瞬间,流量集中回源数据库。
- 排查时先看
TTL、缓存命中率、回源日志和数据库 QPS 是否同一时间突增。 - 修复时不要让所有请求都查数据库,常见做法是互斥锁、逻辑过期和短暂降级。
- 热点数据的过期时间要做随机化或主动续期,避免同一批 key 集中失效。
现象:Redis 没挂,数据库却突然被打满
缓存击穿最容易误导人的地方在于,Redis 本身可能完全正常。连接数没爆、内存没满、慢查询也没有明显堆积,但数据库 QPS 突然冲高,业务接口从平时的几十毫秒陡升到几秒级延迟。

第一步先确认是不是某个热点 key 在同一时间过期。可以从应用日志、缓存 miss 计数、数据库慢日志和 Redis 命中率几个维度交叉核对。如果只有某个商品、活动页、配置项或用户画像接口异常明显,热点 key 引发问题的嫌疑就很大。
redis-cli TTL product:1001 redis-cli --latency redis-cli INFO stats | grep keyspace
分层检查:先别急着扩容数据库
数据库被打满以后,很多人第一反应是加连接池、加只读库或者临时扩容。这里先别急。缓存击穿的核心问题是“太多请求同时回源”,如果不先控制回源流量,扩容只能把问题往后推,没过多久还是会被打穿。
| 检查项 | 证据 | 判断方向 |
|---|---|---|
| 热点 key 是否过期 | TTL product:1001 接近 0 或返回 -2 |
确认是不是同一 key 失效 |
| 缓存命中率是否下滑 | miss 计数短时间突增 | 判断是否有大量请求绕过缓存 |
| 数据库 QPS 是否同步冲高 | 查询同一条记录或同一类 SQL | 确认回源集中在热点数据 |
| 应用是否重复重建缓存 | 日志里多台机器同时查库并 set key | 说明缺少互斥保护 |
证据判断:看 miss、回源和同一条 SQL
如果日志里能看到大量类似 cache miss product:1001,数据库慢日志里又是同一条商品查询反复出现,基本可以确认问题不是“数据库突然变慢”,而是缓存没有挡住热点流量。
cache miss key=product:1001 db query product_id=1001 cost=438ms cache set key=product:1001 ttl=300
这个时候要重点看请求是否同时重建缓存。正常情况下,只有一个请求应该拿到重建资格,其他请求短暂等待、读取旧值或走降级。如果每个请求都去查库再 set 缓存,数据库压力会被瞬间放大数倍。
修复动作:用互斥锁控制回源
互斥锁的思路很直接:缓存未命中时,只有抢到锁的请求可以查数据库并重建缓存;其他请求可以等一小段时间后重试缓存,或者返回兜底数据。这样数据库只承受一次回源,而不是承受同一秒内所有请求。

lockKey := "lock:product:1001"
ok, _ := rdb.SetNX(ctx, lockKey, "1", 3*time.Second).Result()
if ok {
defer rdb.Del(ctx, lockKey)
data := loadProductFromDB(1001)
rdb.Set(ctx, "product:1001", data, 5*time.Minute)
return data
}
time.Sleep(50 * time.Millisecond)
cached := rdb.Get(ctx, "product:1001").Val()
这段代码只是说明实现思路,生产环境里还要处理锁超时、回源失败、空值缓存和重试次数。锁过期时间不能太长,也不能太短;太长会挡住正常恢复流程,太短可能导致多个请求又一起进数据库。
反向验证:命中率回升才算真的恢复
修复以后不要只看接口恢复正常就完事。至少要看四个指标:Redis 命中率是否回升,数据库 QPS 是否回落,互斥锁失败次数是否在可控范围,热点 key 的 TTL 是否分散。命中率回升、DB 压力下降,才说明缓存层重新挡住了流量。
redis-cli TTL product:1001 redis-cli INFO stats | grep keyspace redis-cli GET product:1001
如果命中率没有恢复,继续排查是不是 key 写错、序列化失败、TTL 太短,或者回源失败后没有写入缓存。这里别只盯着 Redis 本身,应用日志里的缓存 set 结果同样关键。
后续清单:热点 key 要提前治理
- 热点 key 的 TTL 加随机偏移,避免同一批 key 同时过期。
- 对核心热点数据使用逻辑过期,后台异步刷新,前台尽量读旧值。
- 缓存空值时设置短 TTL,避免不存在的数据反复打库。
- 给缓存 miss、回源耗时、锁等待次数和 DB QPS 加告警。
- 压测时模拟热点 key 过期,而不是只测缓存命中状态。
常见问题
缓存击穿和缓存雪崩有什么区别?
缓存击穿通常是单个或少数热点 key 失效,流量集中打到数据库;缓存雪崩更像大批 key 同时失效,影响面要大很多。
热点 key 永不过期是不是最简单?
不一定。永不过期能降低击穿风险,但会带来数据一致性问题。更稳妥的做法是逻辑过期、异步刷新或主动更新缓存。
互斥锁会不会让接口更慢?
会增加少量等待时间,但比所有请求同时查数据库更可控。锁等待时间要设置得很短,并配合旧值兜底或降级返回。
空值缓存能解决击穿吗?
空值缓存更适合防缓存穿透,比如查询不存在的数据场景。热点 key 过期导致的击穿,核心还是要控制回源并保护热点缓存。
Linux 磁盘满了但 du 找不到大文件:deleted 文件占用空间怎么排查
- 上一篇
- Linux 磁盘满了但 du 找不到大文件:deleted 文件占用空间怎么排查
- 下一篇
- Redis 过期键通知怎么做自动清理:订阅、补偿扫描和幂等门禁
-
- 数据库 · Redis | 1小时前 | Redis · 缓存设计 · HEXPIRE Hash字段过期 Redis Hash HSETEX
- Redis Hash 字段过期适合哪些数据模型
- 462浏览 收藏
-
- 数据库 · Redis | 5小时前 | Redis · redis 缓存失效 CLIENT TRACKING BCAST 客户端缓存
- Redis 客户端缓存如何用广播模式减少失效消息
- 484浏览 收藏
-
- 数据库 · Redis | 9小时前 |
- Cluster 哈希槽迁移期间客户端请求会发生什么
- 397浏览 收藏
-
- 数据库 · Redis | 13小时前 | Redis · 缓存 · 运维 · redis 缓存 maxmemory-policy 内存淘汰
- 内存淘汰策略怎么选:先区分缓存库与持久数据
- 309浏览 收藏
-
- 数据库 · Redis | 16小时前 |
- 缓存穿透治理:空值、布隆过滤器与回源限流组合
- 105浏览 收藏
-
- 数据库 · Redis | 18小时前 |
- 热点 Key 不扩容也能缓解吗:拆分、复制与本地缓存
- 397浏览 收藏
-
- 数据库 · Redis | 1天前 |
- 分布式锁续期失败后还能继续工作吗:租约与围栏令牌
- 333浏览 收藏
-
- 数据库 · Redis | 1天前 | Redis · 消息订阅 消费者组 XREADGROUP XACK Redis Streams Redis Pub/Sub
- Pub/Sub 与 Streams 不只是是否持久化:订阅模型怎么选
- 220浏览 收藏
-
- 数据库 · Redis | 1天前 | 高并发 · Redis限流 滑动窗口限流 Redis Functions FUNCTION LOAD FCALL
- 用 Redis Functions 封装滑动窗口限流:部署、版本与回滚
- 468浏览 收藏
-
- 数据库 · Redis | 1天前 | Redis · 分页 · 缓存设计 · 排行榜 · Sorted Set · ZREVRANK Redis Sorted Set 排行榜 同分排名 排行榜翻页 历史榜单
- Sorted Set 排行榜如何处理同分、翻页与历史榜单
- 189浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 384次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 458次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 471次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 409次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 237次使用
-
- Golang Mutex互斥锁源码分析
- 2022-12-22 200浏览
-
- 初识Golang Mutex互斥锁的使用
- 2022-12-22 312浏览
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览
-
- Go+Redis实现延迟队列实操
- 2023-02-23 426浏览
-
- 一文搞懂Go语言操作Redis的方法
- 2023-01-07 171浏览

