redis分布式锁最优实践是使用set key value ex seconds nx原子命令占位,抢到锁的请求异步更新,其余请求立即降级返回,避免阻塞;ex过期时间需合理设置,防止残留;相比redisson trylock,该方式延迟更低、更轻量。

用 SET key value EX seconds NX 占坑,不阻塞请求
这是最轻量、延迟影响最小的做法:抢到占位符的请求去查 DB,其余请求直接走降级路径(返回旧值、空值或默认值),不等、不轮询、不自旋。
-
SET user:10086 "loading" EX 5 NX成功 → 异步触发更新任务,当前请求可立即返回 stale 数据或兜底值 - 失败 → 不重试锁,立刻查 DB 并返回(不写缓存),或 fallback 到本地缓存(如 Caffeine)
-
EX 5必须设,避免占位符残留;5 秒要 ≥ 后端查询 P99 × 2,但不宜过长(否则后续请求仍持续击穿)
Redisson RLock.tryLock() 容易让延迟翻倍
很多人以为加锁就安全,结果发现接口超时率上升——根本原因是 tryLock(3, 10, TimeUnit.SECONDS) 的两个时间参数没配对:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 第一个参数(waitTime=3s)太短:大量请求抢不到锁,反复走 DB,QPS 暴涨
- 第二个参数(leaseTime=10s)太长:DB 查询卡住(比如慢 SQL 或 GC pause),锁续期失败,自动释放 → 多个线程并发重建缓存 → 更多请求被阻塞
- 心跳线程依赖业务线程活跃,一旦 DB 查询阻塞主线程,watchdog 就失效
本地缓存 + 随机 TTL 才真能压低感知延迟
单纯靠 Redis 层防击穿,本质是把压力从 DB 转移到锁和网络往返上。真正降低用户侧延迟的是错开请求节奏:
- 在应用进程内加一层
Caffeine,设置expireAfterWrite(1, TimeUnit.SECONDS)+refreshAfterWrite(500, TimeUnit.MILLISECONDS) - TTL 加 ±200ms 随机抖动,让原本集中在 10:00:00 的请求,分散到 09:59:59.8~10:00:00.2
- 这样哪怕 Redis 中 key 过期,部分请求仍能命中本地缓存,不打 DB 也不碰 Redis 锁
异步重建缓存时,别让主请求等结果
抢到占位符的请求,如果同步查 DB 再写 Redis,整个链路耗时就是 DB 耗时 + 网络 RTT。正确做法是:
- 占位成功后,立即返回旧缓存值(如有)或默认值(如
"unavailable") - 另起线程或投递消息(如 Kafka / 线程池)去查 DB、组装数据、
SET user:10086 "real_data" EX 3600、再DEL user:10086:loading - 旧值不是“错误”,而是可用性权衡:用户看到的是 2 秒前的数据,但接口响应稳定在 50ms 内










