分布式锁中的 Watch、Watcher、WatchDog 与订阅
在使用 Redis、ZooKeeper 实现分布式锁时我们总会遇到四个容易混淆的概念Watch、Watcher、WatchDog 和订阅。它们名字相似但作用完全不同甚至分属不同的技术栈。许多初学者经常将 WatchDog 当成 Watch或者不理解为什么 ZK 没有看门狗。一、一句话核心概览WatchZooKeeper 中的一次性监听注册动作用于监听节点变化。WatcherZooKeeper 中的事件回调处理器定义收到事件后执行什么逻辑。WatchDog看门狗RedisRedisson分布式锁中的本地后台续期线程防止锁过期。订阅是一个通用设计模式ZooKeeper 的 Watch 和 Redis 的 Pub/Sub 都是订阅机制的具体实现。二、ZooKeeper 体系Watch 与 Watcher在 ZooKeeper 分布式锁中没有自旋、没有看门狗靠的是临时顺序节点 Watch 机制。1. Watcher监听器对象Watcher 是 ZK 提供的一个回调接口本质上是一个事件处理器。public interface Watcher {void process(WatchedEvent event); // 当事件发生时被调用}你可以自定义 Watcher在里面编写收到事件后的逻辑例如“前一个节点被删除了我要重新尝试获取锁”。2. Watch一次性监听注册Watch 是一个动作给某个 ZNode 注册 Watcher 监听告诉 ZK “我对这个节点的某种变化感兴趣”。一次性一次 Watch 被触发后立刻失效想继续监听必须重新注册。触发条件节点创建、删除、数据变更、子节点变化。3. 分布式锁中的工作流程客户端 A 创建临时顺序节点序号最小获得锁。客户端 B 创建临时顺序节点发现不是最小的于是对前一个节点注册Watch并绑定一个Watcher。客户端 A 释放锁删除节点触发 B 注册的 Watch 事件服务器调用 B 的 Watcher。B 收到通知后重新检查自己是否变成最小节点是则获取锁。这就是 ZooKeeper 实现分布式锁的核心利用一次性 Watch 避免忙等通过 Watcher 回调实现竞争。注意ZK 不需要 WatchDog。因为锁是通过临时节点实现的客户端与 ZK 维持会话心跳一旦会话断开临时节点自动删除锁自然释放无需额外续期。三、Redis 体系WatchDog 看门狗WatchDog 是 Redis 分布式锁中独有的概念与 ZK 的 Watch 毫无关系。1. 为什么需要看门狗Redis 分布式锁通常要给锁设置一个过期时间SET lock_key value NX PX 30000防止客户端宕机后锁永远无法释放。但如果业务执行时间超过了锁的过期时间锁会被提前释放其他线程可能乘虚而入造成并发问题。2. WatchDog 的本质一个后台定时线程只做一件事定期给锁续期保证业务执行期间锁不会过期。3. Redisson 的 WatchDog 机制当客户端成功加锁默认过期时间 30 秒Redisson 会启动一个后台看门狗线程每隔10 秒锁过期时间/3执行一次PEXPIRE lock_key 30000续期。只要客户端不主动释放锁看门狗会持续续命。客户端主动解锁或宕机看门狗停止锁最终在 30 秒后自动删除。关键特性只存在 Redis 锁实现ZK 天然不需要。是客户端本地线程不是网络监听。仅对可重入锁、普通互斥锁生效读写锁等默认不启用。四、通用的订阅模式“订阅”是一个更上层的设计模式客户端向中间件注册感兴趣的资源当资源变化时中间件主动推送消息。1. ZooKeeper 的订阅实现就是前面讲的Watch/Watcher组合。它是一次性订阅触发后需重新注册。2. Redis 的订阅实现Pub/Sub在 Redis 的分布式锁如 Redisson 的公平锁、红锁中通常会使用 Pub/Sub 替代自旋。流程如下客户端 B 抢锁失败订阅一个特定的 Channelredisson_lock__channel。客户端 A 释放锁时向该 Channel 发布一条消息。B 收到消息后再次尝试获取锁。ZK Watch 与 Redis Pub/Sub 的区别对比项ZK WatchRedis PubSub持久性一次性用完即毁持久订阅需要手动取消目的监听节点变化等待解锁通知可靠性强一致保证必收到消息可能丢失无持久化五、四者完整对比表名词所属技术栈本质核心作用在分布式锁中的角色WatcherZooKeeper事件回调接口处理节点变更事件收到前序节点删除事件后唤醒本地线程抢锁WatchZooKeeper一次性监听注册订阅节点变化通知为等待锁而注册的监听避免自旋WatchDogRedis/Redisson本地后台线程定时延长锁过期时间防止业务超时导致锁意外释放订阅通用模式消息推送机制资源变更主动通知ZK 用 WatchRedis 用 PubSub优化抢锁效率六、常见误区与关键澄清1. WatchDog 和 Watch 完全无关Watch是 ZK 的事件监听用来通知“锁被释放了你可以去抢了”。WatchDog是 Redis 的后台续期线程用来延长锁的有效期。两者解决的问题不同一个是通知机制一个是续命机制。2. ZK 为什么不需要看门狗ZK 锁基于临时节点 会话心跳。客户端会不断发送心跳给 ZK 服务器若客户端宕机会话超时临时节点自动被删除锁自动释放。它不需要手动续期因此没有看门狗概念。3. “订阅”不等于 Watch订阅是一种设计模式ZK 的 Watch 是一次性的订阅Redis 的 Pub/Sub 是持久订阅。它们都是订阅模式的具体实现。七、实战一个完整的加解锁流程含多个机制1. Redis 分布式锁Redisson含 WatchDog PubSub客户端 A 执行 Lua 脚本加锁成功启动WatchDog后台续期。客户端 B 加锁失败通过PubSub订阅锁对应的 Channel。A 业务完成主动释放锁并向 Channel 发布解锁消息。B 收到推送重新尝试加锁成功后启动自己的 WatchDog。2. ZooKeeper 分布式锁Curator含 Watch Watcher客户端 A 创建临时顺序节点判断自己序号最小获得锁。客户端 B 创建节点后向前一个节点注册Watch并绑定Watcher回调。A 释放锁删除节点触发 B 的 Watch 事件。B 在Watcher中收到通知再次检查序号如果自己是最小则加锁。整个过程 ZK 通过会话心跳自动保活无需 WatchDog。八、总结区分中间件Watch/Watcher 是 ZK 的原生机制WatchDog 是 Redis 锁的补丁方案订阅是通用模式。理解本质Watch 是注册动作Watcher 是处理对象WatchDog 是定时线程订阅是推送模型。记住作用ZK 靠 Watch 通知抢锁Redis 靠 PubSub 通知抢锁 WatchDog 续期防超时。

相关新闻