热点 Key 击穿是什么
击穿指某一个访问量极高的键在过期瞬间被大量并发请求同时发现「缓存里没有」,于是它们一起去查数据库并一起写回缓存。它与雪崩的区别在规模:雪崩是大批键同时失效,击穿只发生在单个热点键上,但因为该键的 QPS 极高,同样能把数据库压垮。两种主流解法是互斥重建(只允许一个请求去回源,其余等待或返回旧值)与逻辑过期(值里自带过期时间,过期后先返回旧值再异步刷新)。
基本信息
| 互斥重建 | 用 SET lock NX PX 抢一个重建锁,拿到锁的请求回源并写回缓存 |
|---|---|
| 二次确认 | 持锁者在回源前再 GET 一次缓存,避免重复回源 |
| 逻辑过期 | 值内部记录过期时间,读取判定过期后返回旧值并触发异步刷新 |
| 兜底手段 | 本地缓存或快照双键,减少对单一远端键的依赖 |
| 观测指标 | 缓存命中率骤降、单键 QPS 极高、回源耗时上升 |
典型使用场景
- 首页与榜单:单个键承载全站流量,任何时候失效都会引发集中回源
- 秒杀与活动入口:流量在短时间内高度集中,缓存失效的代价被成倍放大
- 大屏与监控面板:固定键被高频轮询,重建期间的并发量不可忽略
- 实时价格与库存展示:要求始终有数据可返回,逻辑过期比阻塞等待更合适
- 发布上线:新版本切换到空缓存时,热点键的首次加载需要保护
互斥重建示意
互斥重建示意
redis-cli GET home:feed # 未命中,进入重建流程
redis-cli SET lock:rebuild:home x NX PX 5000 # 只有一个请求能拿到锁
redis-cli GET home:feed # 持锁者二次确认,避免重复回源
redis-cli SET home:feed '{data}' EX 300 # 回源后写回并设置 TTL
redis-cli DEL lock:rebuild:home # 主动释放,缩短等待时间
redis-cli TTL home:feed # 核对写入结果两种方案对比
| 维度 | 互斥重建 | 逻辑过期 |
|---|---|---|
| 请求是否阻塞 | 未抢到锁的请求需等待或降级 | 始终立即返回,最长返回一次旧值 |
| 实现复杂度 | 低,复用分布式锁思路 | 较高,需要在值里编码过期时间并异步刷新 |
| 并发上限 | 回源被压到 1,热点极高时等待队列成为瓶颈 | 刷新异步进行,不限制读取并发 |
| 数据新鲜度 | 重建完成后即为最新 | 刷新完成前会返回旧值 |
锁的 TTL 要覆盖回源耗时上限:持锁者崩溃或回源超时会让他人一直等,因此除设置合理的锁过期时间外,还应给未抢到锁的请求准备降级路径,例如直接返回旧值或返回兜底数据,而不是无限等待。
互斥重建把并发压到 1,在每秒万级请求的热点键上,等待队列本身会成为新的瓶颈。这类极端热点应叠加进程内本地缓存,把绝大部分请求在应用侧就消化掉,远端缓存只作为兜底。