本文已收录在Github关注我,紧跟本系列专栏文章,咱们下篇再续!

  • 🚀 魔都架构师 | 全网30W技术追随者
  • 🔧 大厂分布式系统/数据中台实战专家
  • 🏆 主导交易系统百万级流量调优 & 车联网平台架构
  • 🧠 AIGC应用开发先行者 | 区块链落地实践者
  • 🌍 以技术驱动创新,我们的征途是改变世界!
  • 👉 实战干货:编程严选网

0 前言

除了“持有锁的进程崩溃、未释放锁”这一经典场景,还会因以下容易被忽视的问题,导致系统进入类似死锁的阻塞状态:

1 客户端本地时钟漂移

若加锁客户端的系统时间被人为或自动回拨,可能导致锁的本地过期时间计算错误,客户端误以为锁已过期而提前续期或释放,其他客户端趁机抢占,造成多客户端同时持有同一把锁,后续释放时又互相覆盖,最终谁都无法正常完成业务,表现得像死锁。

解决方案

启用 NTP 严格同步,或使用 monotonic 时间源;

2 锁续期(看门狗)异常

Redisson“看门狗”机制依赖后台线程周期性地为锁续期。若业务线程因 GC、CPU 调度或网络抖动被长时间挂起,看门狗线程也随之暂停,锁在 Redis 端真正过期;业务恢复后却仍认为锁有效,继续持有,导致后续竞争者无法获取锁,形成阻塞。

解决方案

限制业务逻辑执行时间,设置合理的 watchdog 超时上限。

3 主从切换期间的锁丢失

Redis主从异步复制下:

  • 主节点加锁成功后宕机
  • 从节点升为主但尚未收到该锁的写入

新客户端在新【主节点】上再次加锁成功,两个客户端同时持有同一把锁;当它们都尝试释放锁时,可能互相删除对方的键,造成业务逻辑混乱,后续请求因锁状态不一致而持续等待。

解决方案

启用 Redis 哨兵或集群模式,结合 RedLock 多数派策略。

4 Lua 脚本执行超时

用 Lua 脚本保证“判断-删除”原子性时,若脚本因数据量过大或逻辑复杂执行时间超过 Redis 的 lua-time-limit,Redis 会中断脚本并记录 EVALSHA 失败,但客户端可能未收到失败信号,继续认为锁已释放;其他客户端因键仍存在而无法加锁,系统出现“假死”状态。

解决方案

拆分复杂脚本,缩短执行时间,或改用 pipeline 分批执行。