《ZooKeeper 节点类型与分布式锁原理》
ZooKeeper 节点是有生命周期的,具体取决于节点的类型。ZooKeeper 中的节点类型可分为持久节点(PERSISTENT)、临时节点(EPHEMERAL)以及时序节点(SEQUENTIAL),组合使用可以生成以下 4 种节点类型。
1 四种节点类型
-
持久节点(PERSISTENT):节点创建后一直存在,直到有删除操作主动清除——不会因为创建该节点的客户端会话失效而消失。
-
持久顺序节点(PERSISTENT_SEQUENTIAL):基本特性与持久节点一致。额外特性是,每个父节点会为它的第一级子节点维护一份时序,记录每个子节点创建的先后顺序。创建子节点时可设置该属性,ZooKeeper 会自动为给定节点名加上一个数字后缀作为新的节点名,该数字后缀基于整型最大值向上增长。
-
临时节点(EPHEMERAL):生命周期与客户端会话绑定,客户端会话失效节点会自动被清除。注意:是“会话失效”而非“连接断开”。另外,临时节点下面不能创建子节点。
-
临时顺序节点(EPHEMERAL_SEQUENTIAL):结合了临时节点与会话失效自动清除、顺序节点带自增后缀的特性,常用于实现分布式锁。
2 基于临时顺序节点实现的分布式锁
经典的非阻塞分布式锁流程如下:
- 客户端调用
create()方法创建名为_locknode_/guid-lock-的节点,节点创建类型设置为EPHEMERAL_SEQUENTIAL。 - 客户端调用
getChildren("_locknode_")获取所有已创建的子节点(此处不注册任何 Watcher)。 - 客户端获取到所有子节点 path 后,如果发现自己创建的节点序号最小,就认为该客户端获得了锁。
如果发现自己并非所有子节点中序号最小的,说明还没获得锁。此时客户端需要找到比自己序号小的那个节点,对其调用 exists() 方法并注册事件监听:
- 当被关注的节点被移除时,客户端会收到相应通知;
- 收到通知后再次调用
getChildren("_locknode_")获取所有已创建的子节点,确认自己确实是最小的节点,然后重新进入获取锁的判断流程。
该方案相比“单临时节点锁”的优点在于避免了惊群效应:每个客户端只监听前一个节点,节点释放时只有下一个客户端被唤醒。
阅读 —
·
全站 —