缓存重建失败后应通过异步失败队列重试、设置最大重试次数与退避时间、确保缓存写入成功后再释放锁、动态延长锁过期时间、捕获异常并重置逻辑过期时间等措施保障系统稳定性。

缓存重建失败后,数据一直不更新怎么办
缓存重建失败不是小概率事件,而是高并发场景下的常见风险点。一旦 tryLock 成功、数据库查询或序列化出错、写入 Redis 中断(如网络抖动、OOM、主从同步延迟),就会导致锁被释放但缓存始终为空——后续所有请求都走数据库,击穿问题原样复现。
关键不是“要不要重试”,而是“谁来重试、怎么重试、重试几次”。
- 不要在加锁线程里无限重试:一次失败就卡住整个流程,其他线程持续自旋,CPU 拉满,且无法释放锁
- 必须设置最大重试次数(比如 3 次)和退避时间(如 100ms、200ms、500ms),避免雪崩式重试压垮 DB
- 建议把重建失败的 key 记录到一个失败队列(如
cache_rebuild_fail_queue),由后台定时任务或独立消费者异步重试 - 若业务允许,可在失败时主动删除锁 key(
stringRedisTemplate.delete(lockKey)),防止锁残留;但要确保 delete 操作幂等
逻辑过期方案中,重建线程抛异常导致缓存永远不过期
逻辑过期依赖“先返回旧数据 + 异步重建”的模式,但如果异步线程在执行 queryFromDB() 或 writeToRedis() 时抛出未捕获异常(比如 NPE、SQLTimeoutException),expireTime 就不会被更新,缓存会永远停留在“逻辑过期”状态,后续请求持续拿到脏数据。
这不是一致性问题,是可用性陷阱。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 异步重建必须包裹完整 try-catch,且 catch 块里至少要记录 ERROR 日志 + 上报监控(如 Prometheus counter)
- 重建失败后,应重置逻辑过期时间为当前时间 + 基础 TTL(如
System.currentTimeMillis() + 300_000),避免永久卡死 - 不要用
CompletableFuture.runAsync()直接丢弃异常;推荐用带错误回调的handle()或封装成有 fallback 的线程池任务 - 如果重建失败达阈值(如连续 5 次),可触发告警并自动降级为互斥锁模式,人工介入排查
锁释放时机不对,导致缓存写入失败却已放行
很多实现把 unlock(key) 放在 finally 块里,看似稳妥,但若写缓存操作(stringRedisTemplate.opsForValue().set(...))失败,锁却已释放,其他线程立刻读到空缓存,又去抢锁——形成“锁释放早于缓存落地”的竞态漏洞。
这比锁没释放更危险:它制造了伪成功假象。
- 必须确保缓存写入成功后再释放锁。正确顺序是:
query → build → writeToRedis → unlock -
writeToRedis()要检查返回值(如Boolean类型),失败则手动unlock并抛异常,让上层处理(如重试或降级) - 避免在 finally 里无条件
delete锁 key;可改用 Lua 脚本原子执行“判断锁归属 + 删除”,防止误删他人锁 - 生产环境建议使用 Redisson 的
RLock,它自带看门狗续期和自动释放机制,比手写setIfAbsent+delete更可靠
重建耗时超长,锁自动过期引发多线程并发重建
setIfAbsent(key, "1", 10, TimeUnit.SECONDS) 这类锁的过期时间设得太短,而实际重建耗时(如多表 join + 复杂计算)超过 10 秒,锁提前失效,第二个线程就能抢到锁,两个线程同时查库写缓存——缓存击穿没防住,还引入脏写风险。
这不是参数调优问题,是设计缺陷。
- 锁的过期时间必须 > 最大可能重建耗时(含 DB 延迟毛刺),建议设为业务耗时 P999 + 2~3 秒缓冲
- 不能只靠固定 TTL,要结合看门狗机制:每 1/3 过期时间自动 renew 锁(Redisson 默认支持,手写需另起心跳线程)
- 重建过程中,可通过
stringRedisTemplate.getExpire(lockKey)动态检测锁剩余时间,快到期时主动延长 - 若重建逻辑本身不可控(如依赖外部 HTTP 接口),应在锁内做超时控制(如
Future.get(8, TimeUnit.SECONDS)),超时即放弃并释放锁










