Curator框架提供了一套高级的API, 简化了ZooKeeper的操作. 它增加了很多使用ZooKeeper开发的特性, 可以处理ZooKeeper集群复杂的连接管理和重试机制.
org.apache.zookeeper
zookeeper
3.4.6
org.apache.curator
curator-client
4.0.0
org.apache.curator
curator-framework
4.0.0
org.apache.curator
curator-recipes
4.0.0
CuratorFramework提供的方法:
方法名 | 描述 |
---|---|
create() | 创建操作, 可以调用额外的方法(比如节点类型withMode或者后台处理inBackground), 并在最后调用forPath()指定要操作的ZNode |
checkExists() | 检查ZNode是否存在的操作. 可以调用额外的方法(监控或者后台处理), 并在最后调用forPath()指定要操作的ZNode |
getData() | 获得ZNode节点数据的操作. 可以调用额外的方法(监控、后台处理或者获取状态), 并在最后调用forPath()指定要操作的ZNode |
setData() | 设置ZNode节点数据的操作. 可以调用额外的方法(版本或者后台处理), 并在最后调用forPath()指定要操作的ZNode |
getChildren() | 获得ZNode的子节点列表. 可以调用额外的方法(监控、后台处理或者获取状态), 并在最后调用forPath()指定要操作的ZNode |
delete() | 删除操作. 可以调用额外的方法(版本或者后台处理), 并在最后调用forPath()指定要操作的ZNode |
inTransaction() | 原子ZooKeeper事务. 可以复合create, setData, check, and/or delete 等操作, 然后调用commit()作为一个原子操作提交 |
public class CuratorBase {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
//1 重连策略:每隔1s重连一次,重连10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//2 通过工厂创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
cf.start();
//4 创建一个持久节点
cf.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).inBackground().forPath("/super/c1","c1内容".getBytes());
//5 判断节点是否存在
Stat stat = cf.checkExists().forPath("/super/c1");
if(stat==null){
System.out.println("Node does not exists");
}else {
System.out.println("Node exists and the node version is " +
stat.getVersion());
}
//6 读取节点数据
String ret1 = new String(cf.getData().forPath("/super/c1"));
System.out.println(ret1);
//7 修改节点
cf.setData().forPath("/super/c1", "修改c1内容".getBytes());
String ret2 = new String(cf.getData().forPath("/super/c1"));
System.out.println(ret2);
//8 查看是否有子节点
List list = cf.getChildren().forPath("/super");
for(String p : list){
System.out.println(p);
}
//9 级联删除节点
cf.delete().guaranteed().deletingChildrenIfNeeded().forPath("/super");
}
}
监听根节点
public class CuratorWatcher1 {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
//1 重连策略:每隔1s重连一次,重连10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//2 通过工厂创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
cf.start();
//4 建立一个cache缓存
final NodeCache cache = new NodeCache(cf, "/super", false);
cache.start(true);
// 5 添加监听器
cache.getListenable().addListener(new NodeCacheListener() {
/**
* 方法名称:nodeChanged
* 概要说明:触发事件为创建节点和更新节点,在删除节点的时候并不触发此操作。
*/
@Override
public void nodeChanged() throws Exception {
System.out.println("路径为:" + cache.getCurrentData().getPath());
System.out.println("数据为:" + new String(cache.getCurrentData().getData()));
System.out.println("状态为:" + cache.getCurrentData().getStat());
System.out.println("---------------------------------------");
}
});
Thread.sleep(1000);
cf.create().forPath("/super", "123".getBytes()); //触发
Thread.sleep(1000);
cf.setData().forPath("/super", "456".getBytes()); //触发
Thread.sleep(1000);
cf.delete().forPath("/super"); //不触发
Thread.sleep(Integer.MAX_VALUE);
}
}
路径为:/super
数据为:123
状态为:4294967599,4294967599,1536825947234,1536825947234,0,0,0,0,3,0,4294967599
---------------------------------------
路径为:/super
数据为:456
状态为:4294967599,4294967600,1536825947234,1536825948248,1,0,0,0,3,0,4294967599
---------------------------------------
监听子节点
public class CuratorWatcher2 {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
//1 重连策略:每隔1s重连一次,重连10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//2 通过工厂创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
cf.start();
//4 建立一个PathChildrenCache缓存,第三个参数为是否接受节点数据内容 如果为false则不接受
PathChildrenCache cache = new PathChildrenCache(cf, "/super", true);
//5 在初始化的时候就进行缓存监听
cache.start(StartMode.POST_INITIALIZED_EVENT);
cache.getListenable().addListener(new PathChildrenCacheListener() {
/**
* 方法名称:监听子节点变更
* 概要说明:新建、修改、删除
*/
@Override
public void childEvent(CuratorFramework cf, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
System.out.println("CHILD_ADDED :" + event.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED :" + event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED :" + event.getData().getPath());
break;
default:
break;
}
}
});
//创建根节点
cf.create().forPath("/super", "init".getBytes()); //不触发
//添加子节点
Thread.sleep(1000);
cf.create().forPath("/super/c1", "c1内容".getBytes()); //触发
Thread.sleep(1000);
cf.create().forPath("/super/c2", "c2内容".getBytes()); //触发
//修改子节点
Thread.sleep(1000);
cf.setData().forPath("/super/c1", "c1更新内容".getBytes()); //触发
//删除子节点
Thread.sleep(1000);
cf.delete().forPath("/super/c2"); //触发
//删除本身节点
Thread.sleep(1000);
cf.delete().deletingChildrenIfNeeded().forPath("/super"); //触发, 因为级联删除了c1子节点
Thread.sleep(Integer.MAX_VALUE);
}
}
CHILD_ADDED :/super/c1
CHILD_ADDED :/super/c2
CHILD_UPDATED :/super/c1
CHILD_REMOVED :/super/c2
CHILD_REMOVED :/super/c1
分布式锁
public class Lock {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
static int count = 10;
public static void genarNo(){
try {
count--;
System.out.println(count);
} finally {
}
}
public static void main(String[] args) throws Exception {
//1 重连策略:每隔1s重连一次,重连10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//2 通过工厂创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
cf.start();
//4 分布式锁
final InterProcessMutex lock = new InterProcessMutex(cf, "/super");
final CountDownLatch countdown = new CountDownLatch(1);
for(int i = 0; i < 10; i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
countdown.await();
//加锁
lock.acquire();
//业务处理
genarNo();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss|SSS");
System.out.println(sdf.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
},"t" + i).start();
}
Thread.sleep(100);
countdown.countDown();
}
}
count值: 9 - 0
分布式计数器
public class CuratorAtomicInteger {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
//1 重连策略:每隔1s重连一次,重连10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
//2 通过工厂创建连接
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
cf.start();
//4 使用DistributedAtomicInteger
DistributedAtomicInteger atomicIntger =
new DistributedAtomicInteger(cf, "/super", new RetryNTimes(3, 1000));
//把程序打包在1000台服务器上执行, 最终结果为1000
AtomicValue value = atomicIntger.add(1);
System.out.println(value.succeeded()); //操作是否执行成功
System.out.println(value.postValue()); //add(1)操作之后的值
System.out.println(value.preValue()); //add(1)操作之前的值
}
}
分布式障碍
(1)DistributedDoubleBarrier
同步一个操作的开始和结束. n个Client都准备好后才开始执行后续操作. n个Client都执行完后, 才能退出.
public class CuratorBarrier1 {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
public static void main(String[] args) throws Exception {
for(int i = 0; i < 5; i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.retryPolicy(retryPolicy)
.build();
cf.start();
DistributedDoubleBarrier barrier = new DistributedDoubleBarrier(cf, "/super", 5);
Thread.sleep(1000 * (new Random()).nextInt(3));
System.out.println(Thread.currentThread().getName() + "已经准备");
barrier.enter();
System.out.println("同时开始运行...");
Thread.sleep(1000 * (new Random()).nextInt(3));
System.out.println(Thread.currentThread().getName() + "运行完毕");
barrier.leave();
System.out.println("同时退出运行...");
} catch (Exception e) {
e.printStackTrace();
}
}
},"t" + i).start();
}
}
}
(2)DistributedBarrier
与并发工具类CycleBarrier类似. 客户端对节点设置Barrier, 直到所有Barrier被释放才能对该节点进行操作.
public class CuratorBarrier2 {
//zookeeper地址
static final String CONNECT_ADDR = "192.168.1.130:2181";
//session超时时间
static final int SESSION_OUTTIME = 5000;//ms
static DistributedBarrier barrier = null;
public static void main(String[] args) throws Exception {
for(int i = 0; i < 5; i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString(CONNECT_ADDR)
.sessionTimeoutMs(SESSION_OUTTIME)
.retryPolicy(retryPolicy)
.build();
cf.start();
barrier = new DistributedBarrier(cf, "/super");
System.out.println(Thread.currentThread().getName() + "设置barrier!");
barrier.setBarrier(); //设置barrier
barrier.waitOnBarrier(); //等待
System.out.println("---------开始执行程序----------");
} catch (Exception e) {
e.printStackTrace();
}
}
},"t" + i).start();
}
Thread.sleep(5000);
barrier.removeBarrier(); //释放barrier
}
}