05_zookeeper_原生API使用1(更新)
1. java方式操作远端zookeeper集群概述
步骤:下载zookeeper压缩包并解压, 创建java工程,导入zookeeper相关jar包
(1)下载zookeeper压缩包
http://archive.apache.org/dist/zookeeper/, 下载tar.gz源码包, 并进行解压

(2)创建Java工程
Eclipse ->File->New->Java Project, 输入工程名称,一路Next结束
(3)导入zookeeper相关jar包
* 选中新建的工程并右键,选择 “Build Path”-> “Configure Build Path”
* 切换到”Libraries”, 选择”Add External Jars”
* 先添加zookeeper-3.4.5.jar
* 然后添加zookeeper所依赖的jar包 (lib目录下的所有jar)
* 导入jar包结束
2. 通过Java API连接zookeeper
(1) 创建测试类CreateSession

(2) 连接zk集群
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException; public class CreateSession { //建立和zookeeper集群的连接,并自动周期性发送心跳维护连接
private static ZooKeeper zk; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new myWatcher()); //myWatcher中覆盖process方法,定义Client端对Server发来的哪些event进行处理以及如何处理
Thread.sleep(Integer.MAX_VALUE);
}
} class myWatcher implements Watcher{
@Override
public void process(WatchedEvent event) {
//handle connected event
if ( event.getState()== Event.KeeperState.SyncConnected ) { //连接建立事件的处理
System.out.println("Event: " + event);
System.out.println("=======Client Connected to zookeeper======");
}
}
}
核心API分析: zk = new ZooKeeper("192.168.179.101:2181", 5000, new myWatcher());
1)Zookeeper是API提供的1个类,我们连接zk集群,进行相应的znode操作,都是通过Zookeeper类的实例进行,这个实例就是zk client, 和命令行客户端是同样的角色
2)ZooKeeper实例的创建需要传递3个参数
参数1:connectString
*String类型变量,代表要连接的zk集群服务器,通过逗号分隔,"192.168.179.100:2181,192.168.179.101:2181,192.168.179.102:2181"
*ZooKeeper实例连接zk集群服务器时,将在给定的服务器中随机选择,并不存在特定的顺序
参数2:sessionTimeout
*int型变量,表示Zookeeper实例和zkserver间的超时时间,单位为毫秒
*连接正常连接后,ZooKeeper实例将自动和zkserver间通过心跳信息来维持连接,不需要我们介入
参数3:watcher
*Watcher类实例,通常需要我们自己定义一个类,实现框架提供的Watcher接口中的process方法
*process方法,本质是一个回调函数,先解释什么是回调函数
*回调函数理解:打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。“叫醒”这个行为是旅馆提供的,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,通常在登记入住的时候完成,称为登记回调函数(to register a callback function)
*再看new myWatcher和process函数:当创建1个ZooKeeper实例时,我们传入了1个myWatcher实例,myWatcher类的内部实现了process方法。本质上就是:我们在 “登记入住”(创建ZooKeeper实例)时,在zk集群这家旅馆 “登记” 1个“通知” 服务(process方法), 并且告诉旅馆,在出现某些特定事情的时候才进行通知,并且我带了一个小弟(myWatcher实例),通知给他就行,他收到通知后会进行相应的处理(myWatcher实例调用process方法)
ZooKeeper实例创建中的联动操作
ZooKeeper实例在创建的过程中,会随机挑选1个zkserver创建连接,但这个动作是异步的
也就是说new ZooKeeper()这个函数,并不是在和zkserver建立好连接后,才结束函数;大多数情况下,函数返回后,和zk集群的连接并没有建立完成
这也是Thread.sleep(Integer.MAX_VALUE)出现的原因:new完了,就让当前这个运行的线程休息,一直等待;当连接真正建立的时候,这个session的连接状态会变化为SyncConnected;
zkserver此时会向对应的Client发送1个连接变化事件, 事件的处理则自动由myWatcher实例这个小弟去调用process方法来搞定
3. 通过Java API创建节点(同步方式)
(1) 创建znode节点
import org.apache.zookeeper.*;
import java.io.IOException; public class CreateNode implements Watcher {
private static ZooKeeper zk; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new CreateNode());
Thread.sleep(Integer.MAX_VALUE);
}
@Override
public void process(WatchedEvent event) {//Client端处理连接建立事件,处理动作为添加1个永久节点
// create persistent node if connected
if (event.getState() == Event.KeeperState.SyncConnected) {
//创建znode节点
try {
createNodeSync();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } //create node, synchronized
private void createNodeSync() throws KeeperException, InterruptedException {
System.out.println("Create node with Sync mode");
String path = zk.create("/node_by_java", "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("New Node added: " + path);
}
}
运行该java类,通过终端查看结果:

在zookeeper集群上,通过zkCli.sh客户端连接zookeeper集群,验证节点是否已经添加

核心API分析: path = zk.create("/node_by_java", "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT );
public String create(String path,
byte[] data,
List<ACL> acl,
CreateMode createMode)
throws KeeperException,
InterruptedException
参数1 path:
String类型,表示要在zk集群上创建的znode的绝对路径
参数2 data:
byte数组类型,表示要创建的znode中写入的数据,Java字符串提供getBytes()方法,可以直接将字符串转化为1个byte数组
参数3 acl:
List<ACL>类型,List可以理解为升级版的数组,并且数组中的元素为ACL类型变量,本质上这里指定的是要创建的znode的访问权限
OPEN_ACL_UNSAFE = new ArrayList<ACL>(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE))); 本质上是创建了1个允许任何人进行操作的权限
参数4 createMode:
指定要创建的znode类型
CreateMode.PERSISTENT 永久节点
CreateMode.EPHEMERAL 临时节点
CreateMode.PERSISTENT_SEQUENTIAL 永久顺序节点
CreateMode.EPHEMERAL_SEQUENTIAL 临时顺序节点
返回值:path
String类型,被创建的znode节点的实际路径
需要注意的是,这里的create方式是同步方式,也就意味着:当znode创建完成或者创建中出现异常时,函数才会返回
4. 通过Java API查询子节点列表1(同步方式)
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List; public class GetChildrenSync implements Watcher {
private static ZooKeeper zk; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new GetChildrenSync()); //类实例,该类要实现Watcher类的process函数,定义Client处理哪些zkserver发来的事件event
Thread.sleep(Integer.MAX_VALUE);
} @Override
public void process(WatchedEvent event) { //框架定义的接口,我们要实现Client处理哪些event,如何处理这些event
// 只在连接建立后,查询/的子节点列表
if (event.getState() == Event.KeeperState.SyncConnected) {
//查询子节点列表
try {
getChildrenSync();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } //get children , synchronized
private void getChildrenSync() throws KeeperException, InterruptedException {
System.out.println("Get Children in sync mode");
//false, 不关注子节点列表的变更事件(不注册watcher)
List<String> children = zk.getChildren("/", false);
System.out.println("Children list of / :" + children);
} }
运行java类,通过终端查看结果:

核心API分析: List<String> children = zk.getChildren("/", false);
public List<String> getChildren(String path,
boolean watch)
throws KeeperException,
InterruptedException参数1:path
String类型,指明要查询哪个znode的子节点列表
参数2:watch
boolean类型,false表示只是查询,并不需要zkserver在检测到子节点列表发生变化时,进行事件通知(不关注子节点发生变化的Event)
返回值:List<String>
返回子节点列表,每个子节点通过字符串表示,构成一个“数组”
5. 通过Java API查询子节点列表 (同步 + 设置子节点列表变更的watcher)
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.List; public class GetChildrenSync implements Watcher {
private static ZooKeeper zk;
private String path; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new GetChildrenSync());
Thread.sleep(Integer.MAX_VALUE); } @Override
public void process(WatchedEvent event) {
// “子节点列表发生变化” event的处理
if(event.getType() == Event.EventType.NodeChildrenChanged) {
//再次获取子节点列表
try {
List<String> new_children = zk.getChildren(event.getPath(), true); //event.getPath()返回 哪个znode的子节点列表发生了变化
System.out.println(new_children);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// 连接建立事件的处理
if (event.getState() == Event.KeeperState.SyncConnected) {
//查询子节点列表
try {
getChildrenSync(); //设置关注子节点列表
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} //get children , synchronized
private void getChildrenSync() throws KeeperException, InterruptedException {
System.out.println("Get Children in sync mode");
//true, 关注子节点列表的变更(注册子节点变更watcher)
List<String> children = zk.getChildren("/", true); //关注“/”子节点列表变化event
System.out.println("Children list of / :" + children);
} }
分析:
代码运行时,会首先建立和zkserver的连接,第一次会查询/的子节点列表,并设置了/路径子节点变更的watcher;
通过命令行方式在/添加1个节点,此时zkserver会向java cliet发送子节点发生变化的事件,此时process函数被再次触发,并且执行再次获取子节点列表的操作
要注意process中event的设计顺序,想想看如果检测Event的state是否为SyncConnected是process中首先出现的检测代码,会出现什么情况?(先挖坑)


开始填坑:
zookeeper框架中的WatchedEvent类型的event, 携带了3类信息:
1)当前连接的状态, event.getState() 可以获取:已连接,已断开等
2)事件类型, event.getType() 可以获取: 子节点列表发生变化,节点数据内容发生变化
3)事件关联的znode节点, event.getPath() 可以获取该znode的绝对路径: 子节点列表发生变化,则关联的znode就是父节点
当client和zk集群刚刚建立连接时,zk会向client发送1个连接建立事件,此时事件的连接状态为connected, 事件类型为EventType.None, 事件关联的节点为空(event.getPath==null)
当子节点列表变化的事件发生时,该事件的连接状态也为connected, 事件类型为EventType.NodeChildrenChanged, 事件关联的节点为/
如果将 event.getState() == Event.KeeperState.SyncConnected放在process函数的开始,则只会执行连接建立时的逻辑,并不会执行子节点变更的处理逻辑
严格来说,连接刚刚建立时的逻辑处理应该进行修改,添加event.getType和event.getPath()来更加精确的描述 “连接刚刚建立”
else {
// 连接刚刚建立事件的处理
if (event.getState() == Event.KeeperState.SyncConnected) {
if(event.getType()==Event.EventType.None && event.getPath()==null){
//查询子节点列表
try {
getChildrenSync(); //设置关注子节点列表
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}//
}
Event的状态,类型总结
* 在 Watcher 接口里面,除了回调函数 process 以外,还包含 Event.KeeperState 和 Event.EventType 两个枚举类,分别代表了通知状态和事件类型

6. 查询节点数据(同步方式)
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat; import java.io.IOException;
import java.util.List; public class GetDataSync implements Watcher {
private static ZooKeeper zk;
private String path; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new GetDataSync());
Thread.sleep(Integer.MAX_VALUE);
} @Override
public void process(WatchedEvent event) {
// 连接建立后,获取给定节点数据
if (event.getState() == Event.KeeperState.SyncConnected) {
// 连接刚刚建立
if (event.getType() == Event.EventType.None && event.getPath() == null) {//连接建立后,查询给定路径的znode的数据
//查询给定路径的znode数据
try {
getNodeData("/node_by_java");
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
else if(event.getType()== Event.EventType.NodeDataChanged){
//节点数据发生变化事件
//获取节点的新数据,并再次关注节点数据发生变化的事件
Stat stat = new Stat();
byte[] data = new byte[0];
try {
data = zk.getData(event.getPath(), true, stat);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Updated data is: " + new String(data));
}
} }//process //get node data
private void getNodeData(String path) throws KeeperException, InterruptedException {
System.out.println("Get Node data in sync mode");
Stat stat = new Stat(); //创建1个空状态
byte[] data = zk.getData(path, false, stat); //stat会被更新为节点的最新状态, false表示不关注节点数据发生变更的事件
//byte[] data = zk.getData(path, true, stat); //true表示关注节点数据发生变更的事件,注意一次性
String data2string = new String(data);
System.out.println("Data of " + path + "is: " + data2string);
} }
首先不关注节点数据发生变更,看能够正常获取到znode数据

然后修改为关注节点数据发生变更,通过命令行方式修改数据,查看是否再次获取到更新后的节点数据

7. 删除节点(同步方式)
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException;
import java.util.List; public class DeleteNodeSync implements Watcher {
private static ZooKeeper zk;
private String path;
private int version; public static void main(String args[]) throws IOException, InterruptedException {
//zk will connect to zk server, asynchronized
zk = new ZooKeeper("192.168.179.101:2181", 5000, new DeleteNodeSync());
Thread.sleep(Integer.MAX_VALUE); } @Override
public void process(WatchedEvent event) {
// 连接建立后,删除给定路径的znode
if (event.getState() == Event.KeeperState.SyncConnected) {
// 连接刚刚建立
if (event.getType() == Event.EventType.None && event.getPath() == null) {
//查询子节点列表
try {
delNode("/node_by_java");
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
} }//process //get node data
private void delNode(String path) throws KeeperException, InterruptedException {
System.out.println("Delete Node in sync mode");
//删除给定路径的znode
zk.delete(path, -1); //删除指定路径, 指定dataversion的znode, 如果version指定-1,则删除节点时不进行dataversion校验
System.out.println("Node deleted: "+ path);
//删除后再次查询/子节点列表
List<String> children = zk.getChildren("/", false);
System.out.println("Children list of / is" + children);
} }

05_zookeeper_原生API使用1(更新)的更多相关文章
- PHP数据库操作:从MySQL原生API到PDO
本文将举详细例子向大家展示PHP是如何使用MySQL原生API.MySQLi面向过程.MySQLi面向对象.PDO操作MySQL数据库的. 为了后面的测试,先建立数据库表test.包含表名user,s ...
- Zookeeper系列三:Zookeeper客户端的使用(Zookeeper原生API如何进行调用、ZKClient、Curator)和Zookeeper会话
一.Zookeeper原生API如何进行调用 准备工作: 首先在新建一个maven项目ZK-Demo,然后在pom.xml里面引入zk的依赖 <dependency> <groupI ...
- MySQL原生API、MySQLi面向过程、MySQLi面向对象、PDO操作MySQL
[转载]http://www.cnblogs.com/52fhy/p/5352304.html 本文将举详细例子向大家展示PHP是如何使用MySQL原生API.MySQLi面向过程.MySQLi面向对 ...
- curator框架的使用以及实现分布式锁等应用与zkclient操作zookeeper,简化复杂原生API
打开zookeeper集群 先体会一下原生API有多麻烦(可略过): //地址 static final String ADDR = "192.168.171.128:2181,192.16 ...
- ES7前端异步玩法:async/await理解 js原生API妙用(一)
ES7前端异步玩法:async/await理解 在最新的ES7(ES2017)中提出的前端异步特性:async.await. 什么是async.await? async顾名思义是“异步”的意思,a ...
- ZooKeeper实现配置中心的实例(原生API实现)(转)
说明:要实现配置中心的例子,可以选择的SDK有很多,原生自带的SDK也是不错的选择.比如使用I0Itec,Spring Boot集成等. 大型应用通常会按业务拆分成一个个业务子系统,这些大大小小的子应 ...
- 一个缓存使用案例:Spring Cache VS Caffeine 原生 API
最近在学习本地缓存发现,在 Spring 技术栈的开发中,既可以使用 Spring Cache 的注解形式操作缓存,也可用各种缓存方案的原生 API.那么是否 Spring 官方提供的就是最合适的方案 ...
- jQuery? 回归JavaScript原生API
如今技术日新月异,各类框架库也是层次不穷.即便当年漫山红遍的JQuery(让开发者write less, do more,So Perfect!!)如今也有被替代的大势.但JS原生API写法依旧:并且 ...
- 注解 @RequestParam,@RequestHeader,@CookieValue,Pojo,servlet原生API
1.@RequestParam 我们的超链接:<a href="springMvc/testRequestParam">testRequestParam</a&g ...
随机推荐
- Yii框架2.0的安装过程
Yii框架是个不错的php开发框架,大型项目上都可以使用.和大多框架一样他也是开源,而且采用了mvc结构的. Yii1.*,直接下载然后用脚步可以创建自己的项目了,最近看了下Yii2.0版本的,他推荐 ...
- 使用python的logging模块(转)
一.从一个使用场景开始 开发一个日志系统, 既要把日志输出到控制台, 还要写入日志文件 import logging # 创建一个logger logger = logging.getLogger(' ...
- MySQL单列索引和组合索引的区别介绍(转)
原文:http://database.51cto.com/art/201011/233234.htm MySQL单列索引是我们使用MySQL数据库中经常会见到的,MySQL单列索引和组合索引的区别可能 ...
- jupter nootbok 快捷键、NumPy模块、Pandas模块初识
jupter nootbok 快捷键 插入cell:a b 删除cell:x cell模式的切换:m:Markdown模式 y:code模式 运行cell:shift+enter tab:补全 shi ...
- excel判断单元格包含指定内容的函数用=IF(COUNTIF(A1,"*内容*"),"0","1")
前面我们聊过怎样将Excel包含某字符的单元格填充颜色,这边我们用另外一种方法来实现:excel判断单元格包含指定内容的函数 选中需要显示结果的单元格,假设我们要判断第一行第一列的单元格A1是否含有“ ...
- 最新zencart支付宝插件(支持1.5)
最新zencart支付宝插件(支持1.5) 最新zencart支付宝插件(支持1.5) 支付宝接口的兼容性真不错,时至今日还能用,想利用zencart来做国内时长还真是方便多了,朋友们可以试试. ...
- php int 与 datetime 转换
数据库日期类型是int类型的,该查询结果是datetime类型的 select from_unixtime( `dateline` ) from cdb_posts 如果原来类型是datetime类型 ...
- 初探Nginx服务器的整体架构
高度模块化的设计是 Nginx 的架构基础.Nginx 服务器被分解为多个模块,每个模块就是一个功能模块,只负责自身的功能,模块之间严格遵循“高内聚,低耦合”的原则. 核心模块 核心模块是 Nginx ...
- Tornado 自定义Form,session实现方法
一. 自定义Tornado 验证模块 我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单 ...
- Scala List 用法
1.++[B] 在A元素后面追加B元素 scala> val a = List(1) a: List[Int] = List(1) scala> val b = List(2) b: ...