ZKEssentials读书笔记(四) - 18965050/ZookeeperEssentials GitHub Wiki
- ZK Recipes
屏障(Barrier)
barrier是一种同步状态. 指的是阻塞分布式进程直到达到一定数量后才可以继续进行. ZK实现:
- 设置一路障节点, 比如/zk_barrier
- 启用barrier时, 屏障节点(/zk_barrier)必须存在
- client调用带watch的exists()方法
- 如果返回false,说明屏障消失, 可以进行进行业务处理
- 如果返回true, 说明屏障存在, 进行等待
- 当到达屏障离开状态(exit condition),删除节点/zk_barrier
- watch被调用, 再次通过exist()返回true或false来判断是否可以继续进行
双重屏障(Double Barrier)
双重屏障是一种特殊的屏障,其用来同步一个任务的开始和结束. 当有足够多的进程进入屏障后,才开始执行任务;当所有的进程都执行完各自的任务后,屏障才撤销。 ZK实现:
-
加入屏障
-
每个client在指定的znode(比如/barrier)下创建临时子目录(ephemeral znode),并添加watch
-
一个负责监听(watch)的子节点监听/barrier子目录数量, 如果达到预定的N,则创建ready子节点
-
/barrier子节点发生变化, 触发watch调用,通过
M = getChildren(/barrier, watch=false)
可获取到M数量, 如果比预定数量N小, 继续屏蔽
-
当M==N时,负责监听的子节点在/barrier下创建ready子目录, 并触发加入到barrier的其他节点判断/barrier下是否存在子目录ready
-
-
离开屏障
-
完成的子节点在/barrier目录下删除自己创建出来的子目录
-
通过调用:
M = getChildren(/barrier, watch=True)
获取M数量
-
如果M!=0,屏障存在;M==0,屏障结束
-
上述的流程有个很大的问题, 即羊群效应(herd effect). 这可以通过创建临时有序目录(ephemeral sequential)来解决. 这样每一个节点只要watch其前面的一个子目录, 而不是父目录就可以了
队列(Queue)
分布式队列遵循生产者-消费者模型,并严格按照FIFO的顺序执行. 这在ZK中可以通过有序znode来实现. ZK实现:
-
创建/queue作为父目录
-
生成者调用
ZooKeeper.create( "queue-", SEQUENCE_EPHEMERAL)
创建有序子目录
-
client通过get_children()方法,并找出最小序号目录进行处理, 处理结束删除此目录
-
需要注意的是client 删除子目录可能不成功.这是由于被其他client获得了处理权. 这需要再次delete
锁(Lock)
ZK实现如下:
- 获取锁
- 调用
create("/_locknode_/lock-",CreateMode=EPHEMERAL_SEQUENTIAL)
- 需要获取锁的节点应用调用
getChildren("/_locknode_/lock-", false)
, 注意watch为false - 如果创建目录拥有最小的序号后缀(0000000001),则获取锁
- 否则调用
exists("/_locknode_/<znode path with next lowest sequence number>, True)
.如果返回true,则获取锁;返回false,未获取锁
- 调用
- 释放锁
- 获得锁的节点删除子目录, 触发下一个client获得锁
- 下一个触发的client是序号第二小的节点
领导选举(Leader Election)
还来利用ephemeral sequential znode来实现.序号后缀最小的为leader,其他为follower. 当leader崩溃后, 序号后缀第二小的为leader, 其他为follower
成员管理(Membership)
利用ephemeral znode来实现. 这个比较简单, 不细说了
两阶段提交(Two-phase Commit)
两阶段提交包括两个阶段
- 阶段一: 协调节点(coordinator node)向事务(transaction)的所有参与方节点发出投票请求,事务提交或事务回滚
- 阶段二: 如果事务所有投票节点投票事务提交, 则协调节点决定事务提交. 只要有一个投票节点事务回滚, 则协调节点决定事务回滚
ZK实现:
- 创建一根目录(比如 /2PC_Transactions). 协调节点创建/2PC_Transactions/TX 作为事务目录,并在此目录下创建 tx_result 子目录作为最终的事务结果
- 事务参与节点对/2PC_Transactions/TX/tx_result 节点进行监听
- 协调节点通知事务参与节点进行事务投票
- 事务参与节点在/2PC_Transactions/TX 目录下创建临时znode,并写入事务提交或事务回滚数据
- 协调节点收到/2PC_Transactions/TX 子目录变化通知.并判断数量是否和应有的事务参与节点数量一致
- 一致情况下,分析每个临时子目录数据, 来判断是否事务提交或回滚
- 当所有临时子目录数据为提交时,整个事务提交. 否则事务回滚. 将最终数据写入/2PC_Transactions/TX/tx_result znode中
- 事务参与节点监听到数据变化后, 得知事务是否最终提交或回滚
服务发现(Service Discovery)
通过对子目录变化监听, 可比较简单实现此功能