← 返回题目列表

什么是缓存击穿?如何解决?

高频 中等 第 9 / 26 题 更新于 2026/07/28
缓存击穿热点Key互斥锁

简化版

缓存击穿指一个热点 key 突然失效,大量并发请求同时发现缓存未命中,于是一起查数据库并重建缓存,把数据库打爆。解决方案是互斥锁/单飞机制让一个线程重建缓存,其他请求等待或返回旧值;也可以用逻辑过期、热点永不过期、后台刷新等方式降低风险。

详细版

缓存击穿的重点是“单个热点 key”。它和雪崩、穿透不同:

问题数据是否存在触发点主要方案
击穿存在热点 key 过期互斥锁、逻辑过期、热点续期
雪崩存在大量 key 同时失效TTL 随机、高可用、限流降级
穿透不存在查询不存在数据缓存空值、布隆过滤器

常见做法是:缓存未命中后先抢分布式锁,抢到锁的线程查数据库并回填缓存;没抢到锁的线程短暂等待、重试读缓存,或者直接返回旧值。高并发核心热点更适合逻辑过期:缓存不过期或不物理删除,只在值里保存过期时间,过期后由后台或单个线程异步刷新。

完整版教学

一、击穿的现场是什么样

假设首页有一个爆款商品,QPS 很高。这个商品详情缓存过期的一瞬间,几千个请求同时进来,全部发现 Redis 没有值。如果每个请求都去查数据库并回填缓存,数据库会同时承担几千次相同查询,压力瞬间飙升。

这就是击穿:缓存层对热点 key 的保护突然消失,热点流量直接穿过缓存打到 DB。它的本质不是缓存未命中,而是“热点 + 并发重建”。

二、互斥锁方案怎么做

互斥锁方案的核心是只允许一个请求重建缓存。流程是:请求发现缓存未命中,尝试用 Redis SET NX EX 抢锁;抢到锁的请求查数据库、写缓存、释放锁;没抢到锁的请求等待几十毫秒后再读缓存,或者直接返回兜底。

这个方案实现简单,但要注意锁必须设置过期时间,防止重建线程挂掉导致锁不释放;释放锁要校验 value,防止误删别人的锁;等待方不能无限等,否则会把线程池拖死。

三、逻辑过期为什么更适合超热点

逻辑过期不是让 Redis key 真正过期,而是在缓存 value 中保存一个 expireTime。请求读到缓存后,如果发现逻辑时间过期,不立即删除,也不让所有请求查 DB,而是尝试抢锁异步刷新。抢不到锁的请求先返回旧值。

它的好处是高可用:热点 key 不会突然消失,用户请求始终能拿到一个结果。代价是短时间可能返回旧数据,所以适合商品详情、排行榜、配置展示等能容忍短暂旧值的场景,不适合余额、库存扣减这类强约束读写。

四、热点永不过期不是字面上不管

有些热点 key 会设置很长 TTL,甚至不设置物理过期,由后台任务定时刷新。这也能避免击穿。但“永不过期”不等于永远不更新,必须有后台刷新、变更事件删除/刷新、人工兜底和监控,否则缓存会长期陈旧。

如果热点 key 体量不大,可以把热点列表提前识别出来,单独采用更稳的刷新策略;普通 key 继续用常规 TTL 即可。

五、如何选择方案

读请求必须尽量拿到最新值,可以用互斥锁同步重建,牺牲一点延迟。读请求更看重可用性,可以用逻辑过期或返回旧值,牺牲短暂一致性。热点极高且数据变化不频繁,可以做后台刷新和多级缓存。

还要配合限流。即使互斥锁保护 DB,等待锁的请求也可能堆满线程池,所以等待时间、重试次数、兜底策略都要设上限。

六、面试追问与工程边界

面试官常会追问“互斥锁会不会把请求都堵住”。会,所以等待锁的请求必须有超时上限,不能无限阻塞。可以短暂 sleep 后重试读缓存,也可以直接返回旧值或降级结果。热点极高时,逻辑过期通常比同步等待更稳。

还要注意锁粒度。锁粒度应该是具体业务 key,而不是整个缓存类型,否则一个商品重建会阻塞所有商品。重建失败也要释放锁并记录告警,避免热点 key 长时间无法恢复。

七、常见误区与追问

这道题不能只背概念,要把「缓存击穿」放回真实分布式系统里解释:参与方是谁、状态怎么流转、失败后怎么恢复,以及它在一致性、性能、可用性之间做了什么取舍。

回答层次要讲清的内容容易漏掉的边界
核心结论缓存击穿是热点 key 过期瞬间大量并发请求同时打到数据库,常用互斥锁、逻辑过期和热点永不过期不要停在名词解释
流程机制热点 key 过期 -> 大量请求同时未命中 -> 只有一个线程拿锁重建缓存 -> 其他线程等待或返回旧值 -> 缓存恢复后请求回到缓存说明触发方、存储方、确认点和兜底
工程取舍一个热点商品 key 过期时有 5000 个并发请求,若都查库会形成瞬时尖峰缓存提升吞吐但会引入旧值、热点、内存和失效风暴问题
缓存击穿 面试拆解:
1. 热点 key 过期
2. 大量请求同时未命中
3. 只有一个线程拿锁重建缓存
4. 其他线程等待或返回旧值
5. 缓存恢复后请求回到缓存

记忆钩子:先说明缓存承担的读写压力,再拆穿透、击穿、雪崩、热点、一致性和淘汰策略;回答时要紧扣「缓存击穿」这道题,不要把相邻概念混成一段泛泛的分布式套话。

  • 误区:击穿和穿透一样。 击穿查询的是存在的热点 key,穿透查询的是不存在的数据。
  • 误区:加锁后所有问题都没了。 锁要有超时、降级和防死锁,等待线程也要控制。
  • 误区:热点 key 永不过期没有代价。 需要主动更新或逻辑过期,否则可能长期返回旧值。
  • 追问:逻辑过期怎么做? 缓存值里存 expireAt,过期后先返回旧值,再异步重建。
  • 追问:击穿适合什么方案? 热点 key 识别、互斥重建、逻辑过期和本地缓存。
  • 追问:如何防止重建失败? 保留旧值、短期降级、重试和告警。

八、加强记忆

缓存击穿是“单个热点 key 过期后,大量并发一起回源”。治理核心是避免所有请求同时重建缓存:互斥锁让一个请求查库,逻辑过期让大部分请求先返回旧值,热点永不过期和后台刷新让 key 不突然消失。击穿看单个热点,雪崩看大面积失效,穿透看不存在数据。