目录
curator简介
curator是Netfilx公司开源的一个zookeeper客户端,后捐献给apache,curator框架在zookeeper原生API接口上进行了包装,解决了很多zookeeper客户端非常底层的细节开发。提供zookeeper各种应用场景(比如:分布式锁服务、集群领导选举、共享计数器、缓存机制、分布式队列等)的抽象封装,实现了Fluent风格的API接口,是最好用,最流行的zookeeper的客户端。
导入依赖:
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
1.curator连接zookeeper
package com.cjian.curator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryOneTime;
public class CuratorConnection {
public static void main(String[] args) {
/**
* 重连策略
* new RetryOneTime(3000) 三秒后重连一次,只重连一次
* new RetryNTimes(3, 3000); 每三秒重连一次,重连三次
* new RetryUntilElapsed(10000, 3000); 每三秒重连一次,总等待时间超过10秒后停止重连
* new ExponentialBackoffRetry(1000, 3);随着重连次数的增加,重连的时间增加 baseSleepTimeMs*Math.max(1,random.nextInt(1<<retryCount+1))
*
*/
CuratorFramework client = CuratorFrameworkFactory.builder()
//IP端口号
.connectString("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183")
//会话超时时间
.sessionTimeoutMs(5000)
//重连机制 策略
.retryPolicy(new RetryOneTime(3000))
//命名空间 父节点
.namespace("create")
//构建连接对象
.build();
//打开连接
client.start();
System.out.println(client.isStarted());
//关闭连接
client.close();
}
}
2.创建节点
2.1简单创建
@Test
public void create1() throws Exception {
client.create()
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath("/node1", "node1".getBytes());
System.out.println("创建结束");
}
[zk: 127.0.0.1:2182(CONNECTED) 3] ls /
[zookeeper]
[zk: 127.0.0.1:2182(CONNECTED) 4] ls /
[create, zookeeper]
[zk: 127.0.0.1:2182(CONNECTED) 5] get /create/node1
node1
cZxid = 0x300000025
ctime = Tue Feb 02 09:21:13 CST 2021
mZxid = 0x300000025
mtime = Tue Feb 02 09:21:13 CST 2021
pZxid = 0x300000025
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
2.2 自定义权限
@Test
public void create2() throws Exception {
//自定义权限列表
ArrayList<ACL> acls = new ArrayList<>();
Id id = new Id("ip", "127.0.0.1");
acls.add(new ACL(ZooDefs.Perms.ALL, id));
client.create()
.withMode(CreateMode.PERSISTENT)
.withACL(acls)
.forPath("/node2", "node2".getBytes());
System.out.println("创建结束");
}
[zk: 127.0.0.1:2182(CONNECTED) 7] getAcl /create/node2
'ip,'127.0.0.1
: cdrwa
2.3递归创建
@Test
public void create3() throws Exception {
//递归创建节点树
client.create()
.creatingParentsIfNeeded()//支持递归创建节点
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath("/node3/node31", "node31".getBytes());
}
2.4异步创建
@Test
public void create4() throws Exception {
//异步方式创建节点
client.create()
.creatingParentsIfNeeded()//支持递归创建节点
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node4", "node4".getBytes());
Thread.sleep(5000);
System.out.println("创建结束");
}
/node4
CREATE
创建结束
3.修改节点
3.1 同步修改
@Test
public void set1() throws Exception {
client.setData()
.forPath("/node1", "node11".getBytes());
}
@Test
public void set2() throws Exception {
client.setData()
//指定版本号
.withVersion(-1)
.forPath("/node1", "node22".getBytes());
}
3.2 异步修改
@Test
public void set3() throws Exception {
//异步方式
client.setData()
//指定版本号
.withVersion(-1)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node1", "node33".getBytes());
Thread.sleep(5000);
System.out.println("修改结束");
}
/node1
SET_DATA
修改结束
4.删除节点
4.1同步删除
@Test
public void delete1() throws Exception {
client.delete().forPath("/node1");
}
@Test
public void delete2() throws Exception {
client.delete()
//版本号
.withVersion(-1)
.forPath("/node1");
}
@Test
public void delete3() throws Exception {
client.delete()
//删除包含子节点的节点
.deletingChildrenIfNeeded()
.forPath("/node1");
}
4.2异步删除
@Test
public void delete4() throws Exception {
client.delete()
//删除包含子节点的节点
.deletingChildrenIfNeeded()
.withVersion(-1)
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
}
})
.forPath("/node1");
Thread.sleep(5000);
System.out.println("删除结束");
}
/node1
DELETE
删除结束
5.查看节点数据
5.1同步方式
@Test
public void getData1() throws Exception {
//读取节点数据
byte[] node2s = client.getData().forPath("/node2");
System.out.println(new String(node2s));
}
@Test
public void getData2() throws Exception {
Stat stat = new Stat();
//读取数据时读取节点的属性
byte[] node2s = client.getData()
.storingStatIn(stat).forPath("/node2");
System.out.println(new String(node2s));
System.out.println(stat.getVersion());
}
5.2异步方式
@Test
public void getData3() throws Exception {
Stat stat = new Stat();
//读取数据时读取节点的属性
byte[] node2s = client.getData()
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
//数据
System.out.println(new String(curatorEvent.getData()));
}
}).forPath("/node2");
Thread.sleep(5000);
}
/node2
GET_DATA
node2
6.查看子节点
6.1同步方式
@Test
public void getChild1() throws Exception {
List<String> list = client.getChildren().forPath("/node1");
for (String s : list) {
System.out.println(s);
}
}
node11
6.2 异步方式
@Test
public void getChild2() throws Exception {
client.getChildren()
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
List<String> list = curatorEvent.getChildren();
for (String s : list) {
System.out.println(s);
}
}
}).forPath("/node1");
Thread.sleep(5000);
}
/node1
CHILDREN
node11
7.是否存在
7.1同步方式
@Test
public void exists1() throws Exception {
Stat stat = client.checkExists().forPath("/node1");
System.out.println(stat.getVersion());
}
如果不存在,则stat为null
7.2异步方式
@Test
public void exists2() throws Exception {
client.checkExists()
.inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent)
throws Exception {
//节点路径
System.out.println(curatorEvent.getPath());
//事件类型
System.out.println(curatorEvent.getType());
System.out.println(curatorEvent.getStat().getVersion());
}
}).forPath("/node1");
}
/node1
EXISTS
0
8.监视器
curator提供了两种watcher来监听节点的变化
- NodeCache :之间听某一个特定的节点,监听节点的新增和修改
- PathChildrenCache:监听一个znode的子节点,当一个子节点增加、更新、删除时PathChildrenCache会改变它的状态,会包含最新的子节点,子节点的数据和状态
监视器可重复使用
8.1监视当前节点
@Test
public void watcher1() throws Exception {
//监视某个节点的数据变化
NodeCache nodeCache = new NodeCache(client, "/watcher");
//开启监视器对象
nodeCache.start();
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println(nodeCache.getCurrentData().getPath());
System.out.println(new String(nodeCache.getCurrentData().getData()));
}
});
Thread.sleep(60000);
//关闭监视器对象
nodeCache.close();
}
首先该节点是没有的,当我们在命令窗口执行:create /create/watcher "111" 后,控制台输出:
/watcher
111
当我们在控制台再次执行:set /create/watcher "222" 后,控制台输出:
/watcher
222
8.2 监听子节点
@Test
public void watcher2() throws Exception {
//监视某个子节点的数据变化
//第三个参数为事件中是否可以获取节点的数据
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/watcher",true);
//开启监视器对象
pathChildrenCache.start();
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent)
throws Exception {
System.out.println(pathChildrenCacheEvent.getType());
System.out.println(pathChildrenCacheEvent.getData().getPath());
System.out.println(new String(pathChildrenCacheEvent.getData().getData()));
}
});
Thread.sleep(60000);
//关闭监视器对象
pathChildrenCache.close();
}
首先该节点是没有的,当我们在命令窗口执行:create /create/watcher/watcher1 "11" 后,控制台输出:
CHILD_ADDED
/watcher/watcher1
11
当我们在控制台再次执行: set /create/watcher/watcher1 "123" 后,控制台输出:
CHILD_UPDATED
/watcher/watcher1
123
当我们在控制台再次执行: delete /create/watcher/watcher1 后,控制台输出:
CHILD_REMOVED
/watcher/watcher1
123
9.事务
//事务
@Test
public void tra1() throws Exception {
//开启事务
client.inTransaction().create().forPath("/test1","test1".getBytes())
.and()
.setData().forPath("/notExistsNode","not exists".getBytes())
.and()
//提交事务
.commit();
}
10.分布式锁
package com.cjian.curator;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class CuratorLock {
private static CuratorFramework client;
public static void main(String[] args) throws InterruptedException {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183")
.sessionTimeoutMs(5000)
.retryPolicy(retryPolicy)
//可选项
.namespace("lock")
.build();
client.start();
//排他锁
InterProcessLock interProcessLock = new InterProcessMutex(client, "/lock1");
//读写锁
//InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(client, "/lock1");
Order order = new Order(0,interProcessLock);
for (int i = 0; i < 5; i++) {
new Thread(order).start();
}
Thread.sleep(10000);
System.out.println(order.getNum());
}
}
class Order implements Runnable{
private int num;
private InterProcessLock interProcessLock;
public Order(int num, InterProcessLock interProcessLock) {
this.num = num;
this.interProcessLock = interProcessLock;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
interProcessLock.acquire();
num++;
interProcessLock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}