Curator是基于Zookeeper Client的一套高级API集,
其主要目的是隐藏Zookeeper复杂的连接管理细节,其实现了一些基本的工具,如锁,
缓存等,像
create,
delete,
getData等操作,允许我们链式调用,
被称为fluent,同时也提供了如
命名空间,
自动重连等功能。本文将使用
Curator来实现之前的Master。
-
Curator客户端
-
在使用Curator客户端前,我们需要先通过工厂方法创建客户端
-
Fluent API
-
Fluent API允许我们执行链式调用。比如之前,
我们创建节点的操作为
-
而通过Fluent API大概为
-
create()方法将返回一个
CreateBuilder实例,
后续调用将会对CreateBuilder进行扩展,
Builders也支持delete,
setData,
checkExists,
getChildren等操作。
同时,我们也可以通过inBackground()方法进行异步调用
-
我们也可以通过watched()方法进行进行监听
-
监听器
-
监听器将处理Curator库生成的事件,我们仅需要将通过Curator客户端注册这些监听器即可。
我们需要实现一个CuratorListener
-
然后我们需要注册监听器
-
有一个专门用于监听后台线程发生异常时的监听器UnhandledErrorListener
-
Curator中的状态改变
-
Curator暴露了一些不同于Zookeeper的状态集,比如有
SUSPENDED状态,
使用LOST状态表示会话过期,下面是Curator中的连接状态机
-
还有一个额外的READ_ONLY状态,
但和我们的案例无关,当Zookeeper只读模式被开启,并且Client连接的Server进入只读模式时,
连接将变成只读的,只读的Server将不能参与投票,
这时,Client将丢失任何Zookeeper集群的状态更新。
如果Client发出了更新操作,并且集群中的部分Server能够达到投票数,
那么这种更新操作是可以的。
-
两个边界问题
-
有两个有意思的错误,Curator处理得很好。
第一个是创建有序节点时出现的错误,
第二个则是删除节点时发生的错误。
有序节点:
如果Client在获取到Server返回的有序节点的名称之前,Server崩溃或者Client连接断开了,
那么Client将不能知道创建的节点的名称,这时可能Client需要重新发起调用,为了解决这个问题,
CreateBuilder提供了
withProtection方法,
来告诉Curator客户端用一个唯一标识符作为有序节点的前缀,当Client创建有序节点失败,重试的时候,
就能根据该标识符判断有序节点是否创建成功。
删除保证:
同样,当Client执行delete操作后断开了连接,
那么将不能知道该节点是否被成功删除,
当该节点的存在性关乎到某些资源的请求和释放时,
这就比较关键了,Curator客户端提供了一个
DeleteBuilder接口来保证节点被成功删除(只要Curator客户端实例是有效的)。
-
代码实例
-
Curator提供了多种工具,可见这里。这里主要介绍
LeaderLatch,
LeaderSelector,
PathChildrenCache。
-
Leader Latch
-
LeaderLatch可用于选举Master,如
-
之后我们还需要注册一个LeaderLatchListener监听器,
实现isLeader和notLeader
方法
-
上述代码片段我们放在实现了
LeaderLatchListener接口的
CuratorMasterLatch中,
所以我们还需要注册将自己到LeaderLatch的监听器中
-
Leader Selector
-
LeaderSelector也是用来选举Master的。
但其使用的是监听器接口是LeaderSelectorListener,
我们需要实现takeLeadership
和stateChanged方法
-
实现takeLeadership
和stateChanged
-
类似需要runForMaster
-
Children Cache
-
代码中我们使用PathChildrenCache获取worker列表和task列表。
PathChildrenCache会保存一份本地缓存,当有变化时,
会通过我们注册的监听器通知我们。
-
监听Worker列表有Worker删除时
-
对于任务列表,我们需要监听有新的任务提交时,需要进行分配
-
以上代码可见
CuratorMasterLatch,
CuratorMasterSelector,
CuratorMaster。