zkCli.sh使用
使用zkCli.sh与服务器建立连接的基本语法:
cd /usr/zookeeper/bin
./zkCli.sh -timeout 0 -r -server ip:port
timeout:超时时间,如果在该时间内没收到服务器的心跳信息,则认为该服务器失效了。
-r:只读模式
-server : zookeeper的ip和端口号
./zkCli.sh -timeout 5000 -server 192.168.137.132:2181
可以看到如下客户端提示:
[zk: 192.168.137.132:2181(CONNECTED) 0]
输入h:
ZooKeeper -server host:port cmd args
stat path [watch] 获取节点的状态信息 输出如下:
cZxid = 0x0 --事物操作的id
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0 --最后更新的事物id
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0 --子节点列表
cversion = 0 --子节点版本号
dataVersion = 0 -- 数据版本号
aclVersion = 0 --权限版本号
ephemeralOwner = 0x0 --创建该临时节点的事物ip(非临时节点为0)
dataLength = 0 --节点存储数据的长度
numChildren = 1 --子节点个数
set path data [version]--修改
ls path [watch] --列出某个节点下的所以子节点信息
delquota [-n|-b] path --删除配额
ls2 path [watch] --列出当前节点的所以子节点和状态信息
setAcl path acl --设置权限
setquota -n|-b val path --设置配额
-n 限制子节点个数 val -子节点个数
-b 限制数据值的长度 val - 数据值的长度
path 数据节点
history --执行指令的历史
redo cmdno
printwatches on|off
delete path [version] --删除不包含子节点的节点
rmr path [version]--删除包含子节点的节点
sync path
listquota path --查看配额信息
get path [watch] --获取数据内容和状态信息
create [-s] [-e] path data acl
-s 表示顺序节点
-e 表示临时节点 在客户端会话结束后 节点会自动删除掉
两个可以一起使用
addauth scheme auth
quit
getAcl path
close 连接到其他的服务器后关闭
connect host:port 连接到其他的服务器
可以看到zookeeper的常用命令,这些命令大致可以分为增删改查,在说明这些命令之前,可以先回顾一下zookeeper的数据结构:
它是一个树状的结构:
以node_1为例,他的完整路径是:/node_1
大多数时候使用zookeeper,都是跟这些节点打交道。
使用JAVA API操作 zookeeper
ZK实现一个层次命名空间的数据模型,可以认为他是一个小型的、精简的文件系统。他的每个节点称之为znode,znode除了自身可以包含一些数据外,还能拥有子节点。当节点中的数据发生变化、或者子节点发生变化时,基于watcher机制,会发送相应的通知给订阅状态的客户端。
ZK依赖的jar包在下载的zk包中可以找到。
首先要实例化ZooKeeper对象,指定其中的三个参数,url为ZooKeeper服务器地址,sessionTimeout为会话超时时间。ZooKeeper的会话超时时间由客户端决定。但是ZooKeeper的server端会有两个配置,minSessionTimeout和maxSessionTimeout,前者默认为2倍的tickTime,后者默认20倍tickTime。tickTime也是服务器端的配置项。是Server内部不控制时间逻辑的最小时间单元。如果由客户端发来的sessionTimeout超过minSessionTimeout-maxSessionTimeout这个范围,Server会自动获取二者之一作为sessionTime,然后为这个Client新建一个session对象。最后一个参数为默认的watcher。
此处暂定为null;
ZooKeeper zk = new ZooKeeper("192.168.137.128:2181", 5000, null);
创建节点
通过ZooKeeper的API新增一个znode节点,节点在被创建的时候,需要指定节点的路径(此处为/root)包含字节数据(这里指定”root data”这个字符串)、访问权限(如果不想设置权限,则指定为Ids.OPEN_ACL_UNSAFE),以及创建节点的类型,关于节点的类型参见下述说明:
//创建root节点,其包含的数据为“root data” ,权限访问为开放,所有人都可以访问 节点为持久化节点
zk.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
删除节点
当不需要某个节点,或者某个节点上的数据已经失效,使用delete方法将节点删除。删除时需要指定节点的版本号version,如果设置-1,则匹配所有版本,ZooKeeper会比较删除节点的版本和服务器上的版本是否一致。如果不一致则会抛出异常。
zk.delete("/root", -1);
设置和获取节点的内容
如果想在已有节点中保存数据,可以通过ZooKeeper的setData方法,将数据保存到节点上。也可以通过ZooKeeper的getData方法来获取该节点保存的数据,一个znde中最多保存1MB的数据
// 设置/root的数据,版本号为-1,如果匹配不到相应的节点,则会抛出异常
zk.setData("/root", "hello".getBytes(), -1);
//取得/root节点的数据,并返回其状态。
Stat stat = new Stat();
byte[] data = zk.getData("/root", false, stat);
setData方法设置/root节点的数据为”hello”,getData方法获取root节点上保存的字节数据。false表示不使用默认的watcher。第三个参数stat,是一个传参数,将会返回节点的状态信息
添加子节点
zk支持在已有节点上添加子节点,同样也使用create方法,但是父节点必须存在,否则会抛出异常。
zk.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zk.create("/root/child", "child data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
判断节点是否存在
stat = zk.exists("/root/child", false);
if(stat==null){
//不存在
}else{
//存在
}
watcher实现
当节点状态发生变化时,通过watcher机制,可以让客户端得到通知,watcher主要实现org.apache.ZooKeeper.Watcher接口。节点状态变化主要如下表:
public class MyWatcher implements Watcher {
@Override
public void process(WatchedEvent event) {
if(event.getType()==EventType.NodeCreated){
System.out.println("node created");
}else if(event.getType()==EventType.NodeDataChanged){
System.out.println("node data changed");
}else if(event.getType()==EventType.NodeChildrenChanged){
System.out.println("node children changed");
}else if(event.getType()==EventType.NodeDeleted){
System.out.println("node deleted");
}
}
}
需要注意,ZooKeeper的watcher是一次性的,也就是说,每次在处理完状态变化事件之后,需要重新注册watcher,这一点很让人抓狂。这个特性使得在处理事件和重新加载watcher这段时间发生节点状态的变化无法被感知。
还有两个细节的问题需要关注,ZooKeeper经常发生两种系统异常。
- org.apache.ZooKeeper.KeeperException.ConnectionLossException 客户端与其中一台服务器socket连接出现异常,连接丢失。
- org.apache.ZooKeeper.KeeperException.SessionExpiredException 客户端的session已经超过sessionTimeout,未做任何操作
ConnectionLossException可以通过重试进行处理,客户端根据初始化ZooKeeper时传递服务列表,自动尝试下一个服务端点,而这段时间内,服务端节点变更事件就会丢失
SessionExpiredException 需要应用重新创建一个新的客户端(new ZooKeeper())这时所有的watcher和EPHEMERAL都将失效