← 返回题目列表

Redis 热点缓存重建如何避免大量请求打到数据库?

中等 第 29 / 36 题 更新于 2026/07/30
Redis热点缓存缓存重建

简化版

热点缓存重建要避免“同一时刻大量请求发现缓存失效,然后一起查数据库”。常见方案是互斥锁重建、逻辑过期异步刷新、提前续期、后台定时刷新和降级兜底。核心是让少量请求负责重建,大部分请求不要同时回源。

详细版

热点 key 失效时,普通 Cache Aside 流程会让请求回源数据库并重新写缓存。如果这个 key 每秒有几千次访问,失效瞬间可能有大量线程同时查询数据库,形成击穿。

互斥锁方案是只有抢到锁的请求查数据库并写缓存,其他请求等待、重试或返回旧值。逻辑过期方案是缓存物理上不立刻删除,发现逻辑过期后异步刷新,用户先拿到旧数据。

选型要看业务能否接受旧值。强一致要求高的场景偏互斥重建;读多且可短暂旧值的热点数据,逻辑过期更稳定。

完整版教学

一、热点重建为什么会击穿数据库

缓存失效本身不可怕,可怕的是失效的 key 正好是热点。假设首页配置 key 每秒 8000 次访问,TTL 到点后第一个请求回源数据库很正常,但如果 8000 个请求都同时回源,数据库就会被打穿。

这类问题和缓存雪崩不同:雪崩是大量 key 一起失效,热点重建是少数超级热 key 失效。治理重点也不同。

热点 key 过期
8000 个请求同时 miss
8000 次查数据库
数据库慢 -> 请求堆积 -> 更多超时重试

二、互斥锁重建怎么做

互斥锁思路是:缓存 miss 后先尝试抢锁,抢到锁的线程查数据库并写缓存;没抢到锁的线程短暂等待后重试缓存,或者直接返回降级值。

GET cache
miss -> SET lock NX EX 5
抢到:查 DB -> SET cache -> DEL lock
没抢到:sleep 50ms -> 再 GET cache

锁 TTL 要合理,避免重建线程挂掉导致死锁。删除锁也要注意只删除自己的锁,避免误删别人新加的锁。

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

逻辑过期是在缓存 value 内放过期时间,而 Redis key 本身不过期或设置较长兜底。请求发现逻辑过期后,尝试触发后台刷新;刷新期间仍返回旧值。

这种方式的好处是读请求不被数据库重建阻塞,热点 key 不会突然消失。代价是用户可能短时间读到旧数据。

方案用户体验数据新鲜度数据库压力
直接过期miss 时变慢较新高峰大
互斥重建少量等待较新可控
逻辑过期稳定可能旧最稳

四、提前续期和后台刷新

对于可预测热点,例如首页榜单、活动商品、系统配置,可以在过期前由后台任务主动刷新。这样用户请求几乎不会遇到 miss。

例如 TTL 30 分钟,后台每 25 分钟刷新一次,并加随机抖动,避免多个节点同一时刻刷新同一批 key。

如果刷新失败,旧缓存不要马上删除,可以保留一段兜底时间,同时告警。这样数据库短暂故障不会直接传导到用户请求。

五、降级和监控不能缺

热点重建方案必须配监控:缓存命中率、重建耗时、锁竞争次数、数据库回源 QPS、旧值返回次数、刷新失败次数。

如果数据库已经慢,继续让请求等待重建可能雪上加霜。此时可以返回旧值、默认值、静态兜底页,或者对非核心用户限流。

缓存稳定性不是只靠 Redis 命令实现,而是靠“重建路径可控、失败路径可降级、异常路径可观察”。

六、常见误区与追问

  • 误区:给热点 key 加随机 TTL 就够了。 随机 TTL 防集中失效,但单个超级热点过期仍可能击穿。
  • 误区:互斥锁能保证所有请求都快。 没抢到锁的请求可能等待,锁超时和重建失败也要处理。
  • 误区:逻辑过期没有缺点。 它牺牲了短时间新鲜度,不适合强一致读场景。
  • 追问:旧值返回会不会有问题? 要看业务容忍度,价格、库存和权限类数据要谨慎。
  • 追问:重建失败怎么办? 保留旧值兜底、重试有限次数、告警,并避免请求无限回源。

七、加强记忆

记忆钩子:热点缓存重建的核心不是“谁来查数据库”,而是“只能让少数人查数据库,其他人别一起冲进去”。

回答这题按“热点击穿原因 → 互斥重建 → 逻辑过期 → 后台刷新 → 降级监控”展开。能把旧值容忍度和数据库保护讲清楚,就已经超过背八股的层次。