怎样运用Redis分布式锁Redlock解决击穿死锁_高可用锁实现方案

作者:袖梨 2026-07-11
RedLock不能解决缓存击穿和死锁,仅降低单点故障风险;它不感知缓存生命周期,不内置重试或死锁检测,防击穿需业务层加锁+回填,防死锁需超时控制、看门狗及环路规避。

Redlock 不能解决“击穿”,也不能防止“死锁”——它只降低单点故障导致的锁丢失风险。真正的击穿和死锁,得靠业务层设计+超时控制+看门狗机制。

Redlock 根本不处理缓存击穿

所谓“缓存击穿”,是指某个热点 key 过期瞬间,大量请求穿透缓存直打数据库。Redlock 是分布式互斥工具,不是缓存策略。它对 key 是否过期、是否命中缓存完全无感。

常见误解是:用 Redlock 锁住“查库+回填缓存”那段逻辑,就能防击穿。但问题在于:

  • SET key value NX PX 30000 这类加锁命令本身不关联缓存 key 的生命周期
  • 如果业务中先删缓存再加锁查库,而删缓存操作没原子性,Redlock 完全拦不住并发回源
  • Redlock 加锁失败时抛异常或返回 false,你得自己决定是阻塞重试、降级返回,还是熔断——它不内置重试或兜底逻辑

Redlock 也不保证不死锁,只是让死锁更难发生

Redlock 的“锁自动过期”依赖每个节点上 PX 设置的 TTL,但它无法规避以下死锁场景:

  • 客户端拿到锁后,在业务逻辑里卡死(如死循环、full gc、线程挂起),既不完成操作也不主动解锁,只能等 TTL 到期
  • 网络分区导致部分节点响应超时,客户端误判为加锁失败,但其实某些节点已成功设锁——此时若没执行 unlockInner() 清理,就会残留锁
  • 多个 Redlock 实例间没有协调机制,A 锁等待 B 锁、B 锁等待 A 锁这类环形依赖,Redlock 不检测也不打破

真正防死锁,得靠:

  • 所有加锁调用必须带 waitTimeleaseTime(如 Redisson 的 tryLock(3, 30, TimeUnit.SECONDS)
  • 业务代码必须有明确的超时边界,比如用 CompletableFuture.orTimeout() 包裹核心流程
  • 监控 redis.call('pttl', KEYS[1]) 返回值,在续期前确认锁还有效

Redlock 高可用的前提是节点真正独立

很多人部署了 5 个 Redis 实例,却把它们放在同一台物理机、同一个 Docker Compose 网络、甚至共用一个配置中心——这根本不是 Redlock 要的“独立”。一旦宿主机宕机,5 个节点全跪,多数派瞬间归零。

必须满足:

  • 5 个节点分布在至少 3 个不同可用区(AZ),不能跨 AZ 共享存储或网络平面
  • 每个节点使用独立的 redis.conf,禁用 slaveofreplicaof,不开启 AOF 或仅使用 appendfsync no
  • 客户端连接串不能写死 IP,要用 DNS 或服务发现(如 Nacos)动态感知节点健康状态
  • 加锁时的超时时间(如 commandTimeout)必须远小于锁 TTL,建议 ≤ TTL / 3,否则网络抖动就导致多数派失败

生产环境别手撸 Redlock,直接用 Redisson 的 RedissonRedLock

自己实现 Redlock 容易漏掉关键细节:

  • 没在加锁失败后对已成功节点执行 EVAL ... DEL 清理,导致锁残留
  • System.currentTimeMillis() 计算耗时,忽略时钟漂移(尤其跨机房部署时 NTP 同步误差可能达百毫秒)
  • 解锁时只发给“加锁成功的节点”,但 Redlock 要求向 全部 N 个节点 发送 Lua 脚本,不管之前是否加锁成功

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 更稳、更快、更省资源。

相关文章

精彩推荐