前言

本文隶属于专栏《1000个问题搞定大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见1000个问题搞定大数据技术体系

正文

概念

Zookeeper 中临时顺序节点的生命周期和客户端会话是绑定的,即:
创建节点的客户端会话一且失效,那么这个节点也会被清除。
而且每个临时顺序节点的父节点都会负责记录其子节点创建的先后顺序,并自动为这个子节点分配一个整型数值,以后缀的形式自动追加到节点名中,作为这个节点最终的节点名。

实现流程

Zookeeper 的分布式锁机制正是利用临时顺序节点的上述特性实现的,其基本流程如下

  1. 客户端调用 create() 方法创建父节点 locknode 与其子节点 locknode/guid-lock-,注意所创建节点的类型需要设置为 EPHEMERAL_SEQUENTIAL。
  2. 客户端调用 getchildren(“locknode”) 方法来获取所有已经创建的子节点,同时在这些子节点上注册 Watcher。
  3. 客户端获取了所有子节点之后,如果发现自己在步骤1中创建的子节点是所有子节点中序号最小的,就说明自己已经获取到了锁。
  4. 如果客户端在步骤 3 中发现自己创建的子节点并非是所有子节点中序号最小的, 说明自己还没有获取到锁,需要等待,直至接到 Watcher 发送的子节点变更通知(即其他客户端释放锁)之后,オ能再获取一次子节点,以判断自己是否获取到了锁。

释放锁的过程相对比较简单,删除客户端自己创建的子节点即可。

ZK 实现分布式锁

应用示例

以下是一个 Zookeeper分布式锁的应用示例:

  1. 客户端 A 与客户端 B 都希望获取分布式锁,为此,它们首先要在 locknode 节点下创建一个临时顺序节点 guid-lock-n (n为Zookeeper自动分配的整数),然后立即获取 acnode 下的所有(一级)子节点。
  2. 由于 A 与 B 两个客户端在同一时间争取锁,因此 locknode 下的子节点数量会大于 1。而顺序节点的特点是节点名称后会自动有一个数字编号,先创建的节点数字编号小于后创建的,因此可将子节点按照节点名称后的数字编号从小到大排序,排在第一位的(即数字编号最小的)就是最先创建的顺序节点,该节点的创建者就是争取到锁的客户端。
  3. 接下来,客户端 A 需要判断最小的这个节点是否是自己创建的。如果是,则表示客户端 A 获取到了锁;如果不是,则表示锁已经被其他客户端获取,客户端 A 就要等待该客户端释放锁,也就是等待获取到锁的客户端B把自己创建的节点删除。
  4. 客户端A可以通过监听比自己创建的节点 guid-lock-n 次小的那个顺序节点的删除事件来推测客户端 B 是否已经释放了锁。如果是,此时客户端A可再次获取 locknode 下的所有子节点,将其再次与自己创建的 guid-lock-n 节点对比,直到确定自己创建的 guid-lock-n 已成为 locknode 下的所有子节点中顺序号最小的,就表示自己已获取到了锁。
上一篇 下一篇