1.Curator API
- 简介
- Curator作为Zookeeper的一个高层次封装库,为开发人员封装了Zookeeper的一组开发库,Curator的核心目的是为开发人员管理Zookeeper的相关操作。
- Curator提供的管理操作称为菜单(recipes)。常用菜单有群首选举(leader),锁(lock),屏障(barrier),缓存(cache)等。
- API的使用
- 创建Curator 客户端:
- org.apache.curator.framework.
CuratorFrameworkFactory
#newClient
(String connectString, RetryPolicy retryPolicy) connectString
:表示我们将要连接的Zookeeper服务器的列表。retryPolicy
:指定丢失事件重试操作的处理策略。
- org.apache.curator.framework.
- Curator的API使用属于流畅式API。如同步创建一个znode:
client.create().withMode(CreateMode.EPHEMERAL).forPath("/path",new byte[0]);
对于异步创建znode,需要增加inBackground(): client.create().withMode(CreateMode.EPHEMERAL).inBackground()
.forPath("/path",new byte[0]),这样创建znode的操作会立即返回。 - inBackground的使用可以传入一个上下文对象,通过该参数可以传入一个具体的回调方法的实现,或是一个执行回调的执行器。
inBackground(BackgroundCallback callback)
- BackgroundCallback的实现,在创建操作执行完成后,会调用实现的方法:
processResult(CuratorFramework zclient, CuratorEvent event)
- zclient:表示当前的客户端。
- event:可以获取到事件类型,znode路径,但是没有包含znode的值等信息(可通过断点查看)。
- Curator的监听器
- 监听器负责处理Curator可产生的事件,使用此机制,需要在应用程序中实现一个或多个监听器,并将这些监听器注册到Curator的框架客户端实例中。
- Curator的监听器的监听器分为两种:
- 处理回调方法和监视通知。
- 处理后台任务产生的异常。
- 处理回调方法和监视通知,使用方式如下
CuratorListener curatorListener = new CuratorListener() { public void eventReceived(CuratorFramework zclient, CuratorEvent event) throws Exception { //对于监听器,事件类型一直是 **WATCHED** System.out.println(event.getType()); System.out.println(event.getPath()); byte[] bytes = zclient.getData().forPath(event.getPath()); String string = new String(bytes); System.out.println(string); } }; client.getData().watched().inBackground().forPath("/assgin"); client.getCuratorListenable().addListener(curatorListener);
+ 处理后台异常任务的监听器,使用方式如下 ``` UnhandledErrorListener errorListener = new UnhandledErrorListener() { public void unhandledError(String message, Throwable e) { //异常处理 } }; client.getUnhandledErrorListenable().addListener(errorListener); ```
- 创建Curator 客户端:
2.Curator recipes(菜单)
Leader选举——群首闩(LeaderLatch)
- 简介
- 菜单——群首闩,用于进行master节点的选举,以主-从(master-worker)工作模式为例说明,在主从的工作模式中,主从服务需要首先选举出一个主节点,而这个主节点在主从中必须是唯一的,那么在多个进程想要成为主节点的情况下,那么需要实现互斥排他的功能。对于zookeeper来说,即创建一个临时znode节点,如
/master
,只要有一个进程创建成功,该进程成为master,其他进程就不能进行创建成为worker或者备用主节点。 - 在zookeeper的原生API中,实现此功能,需要很多的代码编写,并且执行效率和可靠性不一定能得到保障,而Curator的菜单——
群首闩LeaderLatch
就提供了这个功能。
- 菜单——群首闩,用于进行master节点的选举,以主-从(master-worker)工作模式为例说明,在主从的工作模式中,主从服务需要首先选举出一个主节点,而这个主节点在主从中必须是唯一的,那么在多个进程想要成为主节点的情况下,那么需要实现互斥排他的功能。对于zookeeper来说,即创建一个临时znode节点,如
- 应用
- 功能说明
- 对所有竞争同一个znode 路径的 LedaerLatch,相互之间会进行交涉,然后随机选举出一个leader。
- 对于成为Leader的进程回调,我们可以通过
LeaderLatchListener
的自定义实现来进行(见案例)。 - 对于客户端的状态的变化可以通过
ConnectionStateListener
的自定义实现来监控(见案例)。
- 参见案例
- https://github.com/November22/iths-redis/tree/master/src/test/java/com/iths/curator/ll
- 案例里面通过一个服务器类模拟服务器间进行竞争,并且在竞争成功后,进行业务处理。
- 功能说明
Leader选举——群首选举器(LeaderSelector)
- LeaderSelector和LeaderLatch的主要区别在于使用的监听器接口不同。LeaderSelector使用的
LeaderSelectorListener
接口,接口定义了takeLeadership
方法,并集成了ConnectionStateListener接口的stateChanged
方法。 - LeaderSelector 的实例创建方法
- public LeaderSelector(CuratorFramework client, String leaderPath, LeaderSelectorListener listener)
- client:Curator框架的客户端实例。
- leaderPath:表示该主节点所参与的集群管理节点群组的Zookeeper路径,即进程间竞争的节点。
listener
:LeaderSelectorListener接口的实现。- 对于LeaderSelectorListener的实现我们需要关注两个方法:
- 来自ConnectionStateListener的方法
public void stateChanged(CuratorFramework client, ConnectionState newState);
,这个方法表示在client的连接状态发生改变时,业务代码进行对应的处理,不过我们可以使用LeaderSelectorListenerAdapter
抽象类,它实现了对client连接状态发生改变时的处理,这样我们只需要关注takeLeadership
方法的处理。 public void takeLeadership(CuratorFramework client) throws Exception;
这个方法在进程获得leader权限之后调用,在该方法调用完成之后,进程释放领导权,各进程再次进行竞争,释放领导权的进程不再参与竞争,除非调用leaderSelector.autoRequeue();方法。
- 来自ConnectionStateListener的方法
- 对于LeaderSelectorListener的实现我们需要关注两个方法:
- 代码实例见 https://github.com/November22/iths-redis/tree/master/src/test/java/com/iths/curator/ls
Lock菜单
- Curator提供的锁,都是基于Zookeepe的特性,实现的具有分布式特性的锁。其中包含有:
InterProcessMutex
:共享锁,即我们常说的分布式锁,同一时间两台机器只有一台能获得同一把锁,并且是可重入的(在实际应用中,我们经常用redis自己实现分布式锁,但是不一定实现了重入功能)。InterProcessReadWriteLock
:分布式环境下的共享读写锁,可类比ReentrantReadWriteLock
实现的功能,排他锁与共享锁。InterProcessSemaphoreV2
:分布式环境下的信号量,即在多个JVM中,给定数量的资源,然后各个JVM的应用按请求顺序执行应用,类注释this semaphore is mostly "fair"
。(InterProcessSemaphore过期了)InterProcessSemaphoreMutex
:分布式下非重入的信号量。
- 案例地址:https://github.com/November22/iths-redis/blob/master/src/test/java/com/iths/zookeeper/CuratorLockTest.java
- (包含
InterProcessMutex
,InterProcessReadWriteLock
,InterProcessSemaphoreV2
案例) - 当我们在分布式的环境下,想要使用类似JDK1.5的一些并发锁的特性,可以着重考虑Curator提供的Lock菜单,虽然我们可以借助其他在分布式环境下各节点公用的服务软件,来实现这些特性(如redis实现分布式锁),但其中的开发量和代码的稳定性不一定能得到保障。
PS:Curator的org.apache.curator.framework.recipes包下,除了前面介绍的leader(群首选举),locks(分布式下的并发锁)外还有其他的一些菜单如,queue(队列),cache(缓存)等等。