互斥锁在多数场景最稳,但需正确实现:用setnx加唯一token和超时,lua脚本原子删锁,超时须短于业务耗时;逻辑过期将过期时间嵌入缓存值中,过期后返回旧数据并异步更新,避免阻塞。

缓存击穿没有“性能最好”的银弹方案,互斥锁(Mutex Lock)在多数业务场景下综合表现最稳——它不依赖额外服务、延迟可控、且能有效拦截穿透请求;但若并发极高或对延迟极度敏感,逻辑过期 + 后台异步更新可能更优,前提是能接受短暂脏数据。
为什么互斥锁不是“加个锁”就完事?
常见错误是直接用 SET key value NX EX 60 做锁,却没处理锁续期、锁误删、或未释放问题。Redis 的单线程特性让 SETNX 成为轻量首选,但必须配合超时和唯一 token:
-
SET lock_key random_token NX EX 30:避免其他客户端误删锁 - 业务逻辑执行完后,用 Lua 脚本原子性校验 token 再
DEL,防止删错 - 锁超时时间要明显短于业务耗时(比如查库+写缓存预计 2s,设锁 5s),否则会阻塞太久
逻辑过期方案里,过期时间到底存在哪?
不是存在 Redis 的 TTL,而是把过期时间作为字段塞进缓存值里,比如 JSON 中的 expireAt 字段。读取时先解析值,再比对当前时间:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 若已逻辑过期,立即返回旧值,同时用
GETSET或SETNX尝试抢占更新权 - 抢到的客户端异步查库、重建缓存;没抢到的继续用旧值,不阻塞
- 注意:不能依赖 Redis 自动淘汰,否则缓存消失后又变回击穿
布隆过滤器真能防住所有击穿?
不能。它只适合“查无此 key 必定不存在”的场景,比如用户 ID 是数字递增、商品 ID 有明确范围。一旦业务允许动态生成 key(如短链、临时 token),布隆过滤器会漏判,反而增加误拒率:
- 初始化阶段必须预热全量 key,否则冷启动时大量 false negative
- 删除 key 时无法从布隆过滤器中移除,只能靠重置或分片隔离
- 内存开销随 key 数量线性增长,1 亿 key 约需 128MB+,不如直接上互斥锁省心
真正容易被忽略的是缓存重建失败后的兜底:无论用哪种方案,都得确保后台更新失败时有告警、有降级(比如返回空对象而非 null)、有重试机制——否则锁释放了,缓存却没写进去,下次请求照旧击穿。










