curator简介
curator是Netflix公司开源的一套zookeeper客户端框架,由java语言编写,包含了对zookeeper源语的高层次、低层次封装,让我们能更简单、更可靠地使用zookeeper。此外,curator还提供了仅用底层开发比较困难的高级特性。
curator常用模块:
- curator-client 提供一些curator客户端底层操作
- curator-framework curator-client的高层次封装,依赖于client。
- curator-recipes curator的“秘籍”,封装了一些高级特性,,如分布式锁、计数器、leader选举、barrier、cache机制等,,注意recipes依赖于client和framework,因此在maven中应允许自动导入
集成curator
我使用的zookeeper3.4.6,curator选用的2.13.0
- maven依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
- CuratorConfig类:注册CuratorFramework,也就是client。
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author zrm
* @Date 2019/3/18 9:52
* @Version 1.0
* @Description curator配置类
*/
@Configuration
public class CuratorConfig {
// Curator客户端
public CuratorFramework client = null;
// zookeeper集群的 ip:port字符串,以','分隔,, 单节点时只写一个
private static final String zkServerIps = "192.168.100.120:2181,192.168.100.121:2181,192.168.100.122:2181";
@Bean
public CuratorFramework curatorFramework(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
// 实例化Curator客户端,Curator的编程风格可以让我们使用方法链的形式完成客户端的实例化
client = CuratorFrameworkFactory.builder() // 使用工厂类来建造客户端的实例对象
.connectString(zkServerIps) // 放入zookeeper服务器ip
.sessionTimeoutMs(10000).retryPolicy(retryPolicy) // 设定会话时间以及重连策略
.build(); // 建立连接通道
// 启动Curator客户端
client.start();
return client;
}
}
- 配置完成后即可开始测试,,
curator操作
curator支持链式编程,用起来是很爽的。这边已经注册了CuratorFramwork,在springboot的测试类中注入 。
- 创建节点
@Test public void create(){ try { client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(null).forPath("/test", "test".getBytes()); } catch (Exception e) { e.printStackTrace(); } }
通过create()方法得到的CreateBuild进行创建节点操作。creatingParentsIfNeeded()自动创建路径的上上级上级节点,,withMode(CreateMode.PERSISTENT),指定节点的创建模式,可选模式为PERSISTENT, PERSISTENT_SEQUENTIAL,,EPHEMERAL, EPHEMERAL_SEQUENTIAL,具体区别如何可以百度。withACL,附加一些该路径的ACL信息, forPath("/test", "test".getBytes()),最基本的,指定创建节点的路径和节点数据,数以byte[]保存。
-
删除节点
@Test public void delete(){ try { client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(0).forPath("/test"); } catch (Exception e) { e.printStackTrace(); } }
deletingChildrenIfNeeded() 删除路径的下级节点,,
guaranteed() 在删除失败时会记录失败操作,然后再后台继续尝试删除操作。
withVersion(0) 指定删除节点的cversion,0表示不限制,,删除操作时如果cversion与输入的不同,删除会失败
forPath("/test") 指定要删除的节点路径
- 查询节点数据
@Test public void get(){ Stat tmpState = null; CuratorWatcher curatorWatcher = new CuratorWatcher() { @Override public void process(WatchedEvent event) throws Exception { System.out.println("出事了~"); System.out.println( "路径:" + event.getPath() + " 状态:" + event.getState() + " 事件类型:" + event.getType()); } }; try { byte[] data = client.getData().storingStatIn(tmpState).usingWatcher(curatorWatcher).forPath("/test"); System.out.println("数据为" + new String(data)); } catch (Exception e) { e.printStackTrace(); } }
storingStatIn(tmpState) 将节点状态存储在tmpState中,,
usingWatcher(curatorWatcher) 通过watcher机制监听节点,
forPath("/test") 指定查询路径
- 修改节点数据
client.setData().withVersion(1).forPath("/test", "v2".getBytes());
分别指定版本和路径,与前面一样。
-
查看节点状态 | 判断节点存在
@Test public void getState(){ try { Stat stat = client.checkExists().forPath("/test"); if (stat == null){ System.out.println("节点不存在"); return; } System.out.println(stat.toString()); } catch (Exception e) { e.printStackTrace(); } }
节点不存在时stat为空。
curator事务支持
@Test
public void inTransaction(){
try {
client.inTransaction().create().forPath("/zrm","v1".getBytes()).and().check().forPath("/zrm").and().setData().forPath("/zrm","v2".getBytes()).and().commit();
} catch (Exception e) {
e.printStackTrace();
}
}
通过and()连接每个操作步骤,commit()提交。
@Test
public void failTransaction(){
try {
client.inTransaction().create().forPath("/fail","v0".getBytes()).and().setData().forPath("/fail","v1".getBytes()).and().create().forPath("/fail","v2".getBytes()).and().commit();
} catch (Exception e) {
e.printStackTrace();
}
}
这个方法重复创建节点会报错,结果是/fail节点没有创建。