心跳检测通过客户端周期性“报活”实现分布式锁续约,加锁成功即启动Watchdog线程,默认每10秒用Lua脚本校验并重设TTL,续期失败不立即释放锁,崩溃时依赖超时自动释放。

心跳检测实现分布式锁续约,核心是让持有锁的客户端在锁过期前主动“报活”,延长锁的生存时间。它不是被动等待超时,而是通过周期性操作维持锁的有效性,避免因业务执行时间波动导致锁提前释放。
心跳线程的触发与启动时机
锁成功获取后立即启动独立的心跳线程(或调度任务),不依赖业务主线程是否阻塞。Redisson 中该线程称为 Watchdog 线程,由 RLock.lock() 调用自动触发。
- 加锁成功即注册续期任务,无需手动开启
- 若使用 tryLock(long waitTime, long leaseTime, TimeUnit unit),leaseTime 决定首次 TTL,也是心跳续期的目标时长
- 客户端关闭或显式 unlock() 时,心跳线程自动终止
心跳检查与续期逻辑
心跳线程定期执行原子校验+重设过期时间的操作,确保只有当前持有者才能续期。
- 默认每 10 秒执行一次(可通过 lockWatchdogTimeout 配置)
- 每次先用 Lua 脚本判断 key 对应的 value 是否仍为当前客户端唯一 ID
- 校验通过则执行 PEXPIRE,将 TTL 重置为原始 leaseTime(如 30 秒)
- 脚本示例:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("pexpire", KEYS[1], ARGV[2]) else return 0 end
异常处理与容错设计
心跳不是无条件运行,需应对网络抖动、节点失联、服务宕机等真实场景。
- 续期失败(如 Redis 响应超时、返回 0)不立即报错,继续下一轮尝试
- 连续多次失败(如 3 次)可能触发告警,但不会自动释放锁——释放必须由业务方显式调用或超时兜底
- 客户端进程崩溃时,心跳停止,锁将在原 leaseTime 后自动过期,其他客户端可竞争获取
- 集群模式下,心跳只作用于当前加锁成功的 Redis 节点,Redisson 内部通过 hash slot 定位和重试保障一致性
与手动心跳的区别
相比自己用 ScheduledExecutorService 实现心跳,框架级心跳更可靠:
- 绑定锁生命周期:线程随锁创建而启,随 unlock 或 JVM 退出而停
- 内置重入识别:同一线程多次 lock() 不重复启新心跳,只维护一个续期任务
- 支持异步非阻塞:基于 Netty 的 HashedWheelTimer,资源占用低、精度高
- 避免误续期:value 使用 UUID + threadId 组合,防止不同线程/实例误续他人锁

















