RedLock不能解决缓存击穿和死锁,仅降低单点故障风险;它不感知缓存生命周期,不内置重试或死锁检测,防击穿需业务层加锁+回填,防死锁需超时控制、看门狗及环路规避。
Redlock 不能解决“击穿”,也不能防止“死锁”——它只降低单点故障导致的锁丢失风险。真正的击穿和死锁,得靠业务层设计+超时控制+看门狗机制。
所谓“缓存击穿”,是指某个热点 key 过期瞬间,大量请求穿透缓存直打数据库。Redlock 是分布式互斥工具,不是缓存策略。它对 key 是否过期、是否命中缓存完全无感。
常见误解是:用 Redlock 锁住“查库+回填缓存”那段逻辑,就能防击穿。但问题在于:
SET key value NX PX 30000 这类加锁命令本身不关联缓存 key 的生命周期Redlock 的“锁自动过期”依赖每个节点上 PX 设置的 TTL,但它无法规避以下死锁场景:
unlockInner() 清理,就会残留锁真正防死锁,得靠:
waitTime 和 leaseTime(如 Redisson 的 tryLock(3, 30, TimeUnit.SECONDS))CompletableFuture.orTimeout() 包裹核心流程redis.call('pttl', KEYS[1]) 返回值,在续期前确认锁还有效很多人部署了 5 个 Redis 实例,却把它们放在同一台物理机、同一个 Docker Compose 网络、甚至共用一个配置中心——这根本不是 Redlock 要的“独立”。一旦宿主机宕机,5 个节点全跪,多数派瞬间归零。
必须满足:
redis.conf,禁用 slaveof、replicaof,不开启 AOF 或仅使用 appendfsync no
commandTimeout)必须远小于锁 TTL,建议 ≤ TTL / 3,否则网络抖动就导致多数派失败RedissonRedLock
自己实现 Redlock 容易漏掉关键细节:
EVAL ... DEL 清理,导致锁残留System.currentTimeMillis() 计算耗时,忽略时钟漂移(尤其跨机房部署时 NTP 同步误差可能达百毫秒)Redisson 的 RedissonRedLock 已封装这些逻辑:
RLock lock1 = redisson.getLock("lock1");RLock lock2 = redisson.getLock("lock2");RLock lock3 = redisson.getLock("lock3");RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);// 同时向 3 个节点申请,至少 2 个成功才算获取锁boolean isLocked = redLock.tryLock(10, 30, TimeUnit.SECONDS);
注意:tryLock(10, 30, ...) 中第一个 10 是最大等待时间,第二个 30 是 leaseTime(看门狗初始 TTL),不是过期时间——看门狗会自动续期,直到 unlock() 或线程终止。
最常被忽略的一点:Redlock 的可靠性提升是有代价的。5 节点 Redlock 的 P99 加锁延迟通常是单节点的 3~5 倍,且吞吐下降明显。如果业务能接受短暂的不一致(如库存超卖容忍 0.001%),单节点 + Redisson 看门狗 + 本地限流,往往比 Redlock 更稳、更快、更省资源。