curator是对zookeeper原生api的封装。原生的api特别难用。
curator提供了流式编程风格,做的非常不错,是目前使用率最高的一种zookeeper框架。
maven依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.10.0</version>
</dependency>
创建客户端连接
//并没有创建会话连接
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString(addr)
.connectionTimeoutMs(timeout)
.sessionTimeoutMs(timeout)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))//初始时间1s,重试连接3次
.build();
//创建会话连接,是个阻塞方法
client.start();
创建节点
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath("/123/456","hello zk".getBytes());
删除节点
client.delete().deletingChildrenIfNeeded().forPath("/123");
查询节点
byte[] bytes = client.getData().forPath("/123/456");
System.out.println(new String(bytes));
更改数据
client.setData().forPath("/123/456","hello hadoop".getBytes());
以上是curator的最基本的用法,可以看出,其流式编程风格很爽。
============================================
以上的操作都是同步的。下面介绍一个异步回调接口BackgroundCallBack.
在程序用用到了这个回调接口,说明程序是异步的。我们知道,异步就需要搞一个线程才行。所以要求传一个线程池,如果不传,就默认自己new一个线程。
比如create节点方法,用了异步接口,那么会在创建完节点后,回调接口。
看例子
private static void createNode(CuratorFramework client,CountDownLatch countDownLatch,ExecutorService executorService) throws Exception {
client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
countDownLatch.countDown();
Thread.sleep(3000);
System.out.println("节点创建成功");
}
},executorService)
.forPath("/123/123", "hello zksss".getBytes());
}
这个流式风格真是太赞了。喜欢死了。
==========================================
zookeeper原生支持通过注册Watcher来进行事件监听,但是其使用并不是特别方便,需要开发人员自己反复注册Watcher,比较繁琐。curator引入了cache来实现zookeeper服务端事件的监听。Cache是Curator中对时间监听的包装,其对事件的监听其实可以近似看作是一个本地缓存视图和远程zookeeper视图的对比过程。
cache分为两类监听类型,节点监听和子节点监听
NodeCache用于监听指定zookeeper数据节点本身的变化。NodeCacheListener是回调接口。
任何节点的变化,包括新增节点,修改数据,删除节点等,都会回调此方法。
与原生方法不同的是,curator将监听功能单独抽象出来,类似于一个监听模块。
这个功能在另一个maven模块中
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.10.0</version>
</dependency>
String nodePath = "/123/456";
NodeCache cache = new NodeCache(client,nodePath);
cache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("节点数据改变了,或者节点被删了");
cache.getCurrentData().getData();
cache.getCurrentData().getPath();
cache.getCurrentData().getStat();
}
});
cache.start();
=========================================
分布式锁
String lockPath = "/123/111";
InterProcessMutex lock = new InterProcessMutex(client,lockPath);
lock.acquire();
//do something
lock.release();
也就是说直接给出了分布式锁的实现。原理是客户端创建锁节点,执行完毕后再删除锁节点。一个客户端先检查是否有锁节点,如果没有,说明可以执行,则创建锁节点去执行。如果有锁节点,则说明现在锁在别的客户端那里,自己则需要等待。
分布式计数器
分布式计数器的一个典型应用场景是统计在线人数。
指定一个zookeeper节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现技术功能。
通过类DistributedAtomicInteger来实现。
分布式Barrier
Barrier是一种用来控制多线程之间同步的经典方式,在JDK中也自带了CyclicBarrier实现。
curator用DistributeBarrier类来实现。