zookeeper是分布式协同领域当之无愧的NO1,数据模型和api都非常简单。zookeeper广泛用于集群管理,分布式锁,服务注册发现,master选举等。
zookeeper的数据模型
zookeeper数据模型使用类似文件系统的树形结构,每一个树节点叫做znode。 各种zookeeper的使用场景,归根结底都是对znode的增删改查操作,因此使用java操作znode就成为最基础的知识。
下图是一个服务注册发现的例子,在zookeeper根节点 / 下创建/service节点,/service节点下有两个子节点,分别保存了服务实例instance-1 和 instance-2。
使用java操作znode
接下来介绍如何使用zookeeper原生api操作znode的方法。
- 在pom文件中引入如下依赖
org.apache.zookeeper
zookeeper
3.6.0
- 连接zookeeper集群
通过创建ZooKeeper实例连接zookeeper集群。我们采用异步方式:当watcher监听到SyncConnected事件时,表示服务端已经就绪,客户端可以访问数据 了。
public ZooKeeper connect() throws InterruptedException, IOException {
//host为zookeeper集群信息,如果有多个服务节点,中间用逗号隔开ip1:port1,ip2:port2,ip3:port
String host = "ip:port";
zk= new ZooKeeper(host, 2000, new Watcher() {
@Override
public void process(WatchedEvent event) {
//当客户端和服务端建立session后,会通知客户端
System.out.println(event.getState());
if (Event.KeeperState.SyncConnected == event.getState()){
conncetedLatch.countDown();
}
}
});
conncetedLatch.await();
System.out.println("Connected to server");
return zk;
}
- 创建节点
zk.create("/service", "hello".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.CONTAINER);
zk.create("/service/instance-1", "10.92.211.13:8080".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL );
zk.create("/service/instance-2", "10.92.211.14:8080".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT );
创建了三个节点,其中:
/service为容器节点,表示该节点会包含子节点,如果子节点全部删除了,那么该节点会自动删除;
/service/instance-1为临时节点,如果客户端会话超期,节点会被自动删除;
/service/instance-2位永久节点,会一直保留。
- 判断节点是否存在
String path = "/service/instance-2";
Stat stat = zk.exists(path, true);
if (null != stat){
System.out.println("node " + path + "current version: " + stat.getVersion());
}
else {
System.out.println("Node not exists");
}
如果节点存在,exists方法会返回一个Stat 对象,该对象描述了节点当前id,版本,最后更新事件,权限类型等信息,如果节点不存在,返回null。
- 从节点读取数据
Stat stat = zk.exists("/service/instance-2", true);
if (null != stat){
byte[] bytes = zk.getData("/service/instance-2", null, stat);
System.out.println(new String(bytes, "UTF-8"));
}
else {
System.out.println("Node not exists");
}
读取数据时,需要确保节点存在。
- 设置节点数据
String path = "/service/instance-1";
int preVersion = zk.exists(path, false).getVersion();
System.out.println("Pre version:" + preVersion);
Stat stat = zk.setData(path, "10.92.211.13:8082".getBytes(), preVersion);
System.out.println("Aft version:" + stat.getVersion());
zookeeper使用CAS的方式更新节点数据,从而保证多个客户端更新时不会出错,因此,更新数据时需要传入持有的版本号。
- 删除节点
String path = "/service/instance-2";
zk.delete(path, zk.exists(path, false).getVersion());
- 断开客户端连接
zk.close();
以上就是使用zookeeper原生的java api 操作znode的入门教程。 Netflix公司开源的一套zookeeper客户端框Curator,可以更方便地操作znode,以后再给大家介绍。
由于zookeeper原生的api使用起来不方便,实际的项目中一般使用Apache Curator等框架进行开发。可以参考
5分钟学习zookeeper:使用Curator 操作zookeeper事半功倍