Curator:zk api的高级封装库
它增加了很多使用ZooKeeper开发的特性,可以处理ZooKeeper集群复杂的连接管理和重试机制。 这些特性包括:
- 自动化的连接管理:重新建立到zk的连接和重试机制存在的一些潜在错误case.
- 清理API:
- 简化了原生的zk的方法,时间等
- 提供了一个现代的流式接口
- 提供了Recipes实现
curator包含了如下几个包:
- curator-framework:对zk的底层api的一些封装
- curator-client:提供一些客户端的操作,例如重试策略等
- curator-recipes:封装了一些高级特性:如cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等。
监听器
监听器(listener)负责处理Curator库锁产生的事件,使用这种机制,应用程序中会实现一个或多个监听器,并将这些监听器注册到Curator的框架客户端实例中,当事件发生时,这些事件就会传递给所有已注册的监听器。
两种边界情况
- 有序节点的情况:createBuilder提供了一个withProtection方法来通知curator客户端,在创建的有序节点前添加一个唯一标识符,如果create操作失败了,客户端就会开始重试操作,而重试操作的一个步骤就是验证是否存在一个节点包含这一个唯一标识符。
- 删除节点的保障:DeleteBuilder接口中定义的guaranteed方法,可以确保删除操作能够一定成功。
zk客户端和zk服务器间主要可能存在下面几种异常情况:
- 短暂失去连接:此时客户端检测到与服务端的连接已经断开,但是服务端维护的客户端session尚未过期,之后客户端和服务端重新建立了连接;当客户端重新连接后,由于session没有过期,zookeeper能够保证连接恢复后保持正常服务。
- 失去连接时间很长:此时服务器相对于客户端的session已经过期了,与先前session相关的watcher和ephemeral的路径和数据都会消失;当Curator重新创建了与zk的连接后,会获取到session expired异常,Curator会销毁先前的session,并且会创建一个新的session,需要注意的是,与之前session相关的watcher和ephemeral类型的路径和数据在新的session中也不会存在,需要开发者在CuratorFramework.getConnectionStateListenable().addListener()中添加状态监听事件,对ConnectionState.LOST事件进行监听,当session过期后,使得之前的session状态得以恢复。对于ephemeral类型,在客户端应该保持数据的状态,以便及时恢复。
- 客户端重新启动:不论先前的zk session是否已经过期,都需要重新创建临时节点、添加数据和watch事件,先前的session也会在稍后的一段时间内过期。
- Zk服务器重新启动:由于zk将session信息存放到了硬盘上,因此重启后,先前未过期的session仍然存在,在zk服务器启动后,客户端与zk服务器创建新的连接,并使用先前的session,与1相同。
- 需要注意的是,当session过期了,在session过期期间另外的客户端修改了zk的值,那么这个修改在客户端重新连接到zk上时,zk客户端不会接收到这个修改的watch事件(尽管添加了watch),如果需要严格的watch逻辑,就需要在curator的状态监控中添加逻辑
curator中状态转换
curator食谱(高级特性)
缓存
Path Cache path cache用来监控一个ZNode的子节点。当一个子节点增加,更新,删除时,Path Cache会改变它的状态, 会包含最新的子节点, 子节点的数据和状态,而状态的更变将通过PathChildrenCacheListener通知。涉及到的四个类:
- PathChildrenCache
- PathChildrenCacheEvent
- PathChildrenCacheListener
- ChildData
Node Cache 只是监听某一个特定的节点。
- NodeCache
- NodeCacheListener
- ChildData
Tree Cache Tree Cache可以监控整个树上的所有节点,类似于上面的两种组合:
- TreeCache
- TreeCacheListener
- TreeCacheEvent
- childData
leader选举
指派一个进程作为组织者,将任务分发给各节点。在任务开始前,哪个节点都不知道谁是leader或者coordinator。当选举算法开始执行后, 每个节点最终会得到一个唯一的节点作为任务leader.
LeaderLatch
leaderLatch = new LeaderLatch(client,"/master",myid)
- start()/close()
- LeaderWatcherListener
- hasLeaderShip
一旦启动,Leaderlathch会和其他使用相同的latch path的其它leaderLatch交涉,然后其中一个最终会被选举为leader.一旦不使用LeaderLatch了,必须调用close方法。
异常处理: LeaderLatch实例可以增加ConnectionStateListener来监听网络连接问题。 当 SUSPENDED 或 LOST 时, leader不再认为自己还是leader。当LOST后连接重连后RECONNECTED,LeaderLatch会删除先前的ZNode然后重新创建一个。LeaderLatch用户必须考虑导致leadership丢失的连接问题。 强烈推荐你使用ConnectionStateListener。
LeaderSelector 主要涉及如下几个类:
- LeaderSelector
- LeaderSelectorListener
- LeaderSelectorListenerAdapter
- CancelLeadershipException
分布式锁
- 1、推荐使用ConnectionStateListener监控连接的状态,因为当连接LOST时你不再拥有锁
- 2、分布式的锁全局同步, 这意味着任何一个时间点不会有两个客户端都拥有相同的锁。
可重入共享锁-shared reentrant lock
由InterProcessMutex来实现
不可重入共享锁—Shared Lock
是InterProcessSemaphoreMutex实现
可重入读写锁—Shared Reentrant Read Write Lock
可重入读写锁主要由两个类实现:InterProcessReadWriteLock、InterProcessMutex。使用时首先创建一个InterProcessReadWriteLock实例,然后再根据你的需求得到读锁或者写锁,读写锁的类型是InterProcessMutex。
信号量—Shared Semaphore
有两种方式可以决定semaphore的最大租约数。第一种方式是用户给定path并且指定最大LeaseSize。第二种方式用户给定path并且使用SharedCountReader类。
多共享锁对象 —Multi Shared Lock
Multi Shared Lock是一个锁的容器。 当调用acquire(), 所有的锁都会被acquire(),如果请求失败,所有的锁都会被release。
分布式计数器 计数器是用来计数的, 利用ZooKeeper可以实现一个集群共享的计数器。 只要使用相同的path就可以得到最新的计数器值, 这是由ZooKeeper的一致性保证的。Curator有两个计数器, 一个是用int来计数(SharedCount),一个用long来计数(DistributedAtomicLong)。
分布式屏障—Barrier 分布式Barrier是这样一个类: 它会阻塞所有节点上的等待进程,直到某一个被满足, 然后所有的节点继续进行。