一、引入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
</dependency>
<!-- curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
二、环境
JDK1.8
win10下zookeeper3.6.2
三、代码
Curator简单操作zookeeper,CRUD、监听节点数据和子节点、leader选举。
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.CuratorCache;
import org.apache.curator.framework.recipes.cache.CuratorCacheListener;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListener;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;
import org.junit.jupiter.api.Test;
import java.util.Scanner;
/**
* 功能描述:
* zookeeper测试
*
* @author test
* @date 2021-07-26 10:17
**/
public class ZooTest {
private static final String ADDRESS = "localhost:2181";
private static final String PATH = "/child";
private static final RetryPolicy retryPolicy = new ExponentialBackoffRetry(2000, 30000);
/***
* 创建zookeeper节点
* @author test
* @date 2021-07-26 13:22
**/
@Test
public void createNode() throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
curatorFramework.create()
// 递归创建,如果没有父节点,自动创建父节点
.creatingParentsIfNeeded()
// 设置节点类型
.withMode(CreateMode.PERSISTENT)
.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
.forPath(PATH + "/child2", "child2 data".getBytes());
curatorFramework.close();
}
/***
* 获取节点信息
* @author test
* @date 2021-07-26 13:23
**/
@Test
public void getNode() throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
byte[] data = curatorFramework.getData().forPath(PATH);
System.out.printf("节点数据:%s\n", new String(data));
curatorFramework.getData().usingWatcher((Watcher) watchedEvent -> System.out.printf("watcher机制触发:%s\n", watchedEvent));
curatorFramework.close();
}
/***
* 设置节点信息
* @author test
* @date 2021-07-26 13:23
**/
@Test
public void setNode() throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
Stat stat = curatorFramework.setData().withVersion(-1).forPath(PATH, "child1 change data".getBytes());
System.out.printf("修改后版本:%s\n", stat.getVersion());
curatorFramework.close();
}
/***
* 删除节点
* @author test
* @date 2021-07-26 13:23
**/
@Test
public void deleteNode() throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
curatorFramework.delete().deletingChildrenIfNeeded().forPath(PATH);
curatorFramework.close();
}
/***
* 监听节点数据变化
* Curator提供了三种Watcher(Cache)来监听结点的变化:
* Path Cache:监视一个路径下1)孩子结点的创建、2)删除,3)以及结点数据的更新。产生的事件会传递给注册的PathChildrenCacheListener。
* Node Cache:监视一个结点的创建、更新、删除,并将结点的数据缓存在本地。
* Tree Cache:Path Cache和Node Cache的“合体”,监视路径下的创建、更新、删除事件,并缓存路径下所有孩子结点的数据。
* @author test
* @date 2021-07-26 11:06
**/
@Test
public void watchDataOfNode() {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
CuratorCache cache = CuratorCache.builder(curatorFramework, PATH).build();
CuratorCacheListener listener = CuratorCacheListener.builder()
.forNodeCache(() -> System.out.printf("节点数据变化!变化后数据:%s\n", new String(curatorFramework.getData().forPath(PATH))))
.build();
cache.listenable().addListener(listener);
cache.start();
// 暂停
new Scanner(System.in).next();
cache.close();
curatorFramework.close();
}
/***
* 监听子节点变化
* @author test
* @date 2021-07-26 13:24
**/
@Test
public void watchPathOfNode() {
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
CuratorCache cache = CuratorCache.builder(curatorFramework, PATH).build();
CuratorCacheListener listener = CuratorCacheListener.builder()
.forPathChildrenCache(PATH, curatorFramework, (client, event) -> {
String path = null == event.getData() ? "" : event.getData().getPath();
byte[] data = null == event.getData() ? new byte[] {} : event.getData().getData();
System.out.printf("子节点事件类型:%s,路径:%s,数据:%s\n", event.getType(), path, null == data ? "" : new String(data));
})
.build();
cache.listenable().addListener(listener);
cache.start();
// 暂停
new Scanner(System.in).next();
cache.close();
curatorFramework.close();
}
/**
* 模拟选举leader
* 当集群里的某个服务down机时,我们可能要从slave结点里选出一个作为新的master,这时就需要一套能在分布式环境中自动协调的Leader选举方法。
* Curator提供了LeaderSelector监听器实现Leader选举功能。同一时刻,只有一个Listener会进入takeLeadership()方法,说明它是当前的Leader。
* 注意:当Listener从takeLeadership()退出时就说明它放弃了“Leader身份”,这时Curator会利用Zookeeper再从剩余的Listener中选出一个新的Leader。
* autoRequeue()方法使放弃Leadership的Listener有机会重新获得Leadership,如果不设置的话放弃了的Listener是不会再变成Leader的。
* @author test
* @date 2021-07-26 13:25
**/
@Test
public void selectLeader() {
// 1. 连接zookeeper
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(ADDRESS, retryPolicy);
curatorFramework.start();
LeaderSelectorListener listener = new LeaderSelectorListener() {
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
System.out.println(Thread.currentThread().getName() + " take leadership!");
// takeLeadership() method should only return when leadership is being relinquished.
Thread.sleep(5000L);
System.out.println(Thread.currentThread().getName() + " relinquish leadership!");
}
@Override
public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
}
};
new Thread(() -> registerListener(curatorFramework, listener)).start();
new Thread(() -> registerListener(curatorFramework, listener)).start();
new Thread(() -> registerListener(curatorFramework, listener)).start();
// 暂停
new Scanner(System.in).next();
curatorFramework.close();
}
/**
* 注册监听器
* @author test
* @date 2021-07-26 13:25
* @param client zookeeper客户端
* @param listener 选举监听
**/
private void registerListener(CuratorFramework client, LeaderSelectorListener listener) {
LeaderSelector selector = new LeaderSelector(client, PATH, listener);
selector.autoRequeue();
selector.start();
}
}