配置
创建默认配置文件zoo.cfg内容如下
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
启动服务器命令
bin/zkServer.sh start
常用命令
ZooKeeper服务命令:
在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作
- 启动ZK服务: sh bin/zkServer.sh start
- 查看ZK服务状态: sh bin/zkServer.sh status
- 停止ZK服务: sh bin/zkServer.sh stop
- 重启ZK服务: sh bin/zkServer.sh restart
- 5.
#
客户端连接远程服务器
zkCli.sh -server 127.0.0.1:2181
操作命令
- 查:
- 查询根目录:
[zkshell: 8] ls /
[zookeeper]
- 增
[zkshell: 9] create /zk_test my_data
Created /zk_test
[zkshell: 11] ls /
[zookeeper, zk_test]
可以创建永久(默认)和临时节点
创建临时节点 使用-s命令
create -e /SecondZnode “Ephemeral-data"
- 内容查询
[zkshell: 12] get /zk_test
my_data
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 5
mtime = Fri Jun 05 13:57:06 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0
dataLength = 7
numChildren = 0
ephemeralOwner值不再是0,表示这个临时节点的版本号,如果是永久节点则其值为 0x0
junk接口已过期、可以使用-s 和-w参数
[zk: 127.0.0.1:2181(CONNECTED) 8] get -s /zk_test
my_data
cZxid = 0x2
ctime = Fri May 11 21:10:00 CST 2018
mZxid = 0x2
mtime = Fri May 11 21:10:00 CST 2018
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
[zk: 127.0.0.1:2181(CONNECTED) 9] get -w /zk_test
my_data
- 改
[zkshell: 14] set /zk_test junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0
[zkshell: 15] get /zk_test
junk
cZxid = 5
ctime = Fri Jun 05 13:57:06 PDT 2009
mZxid = 6
mtime = Fri Jun 05 14:01:52 PDT 2009
pZxid = 5
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0
dataLength = 4
numChildren = 0
- 删
[zkshell: 16] delete /zk_test
[zkshell: 17] ls /
[zookeeper]
[zkshell: 18]
- 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
- 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
- 创建文件,并设置初始内容: create /zk “test” 创建一个新的 znode节点“ zk ”以及与它关联的字符串
- 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
- 修改文件内容: set /zk “zkbak” 对 zk 所关联的字符串进行设置
- 删除文件: delete /zk 将刚才创建的 znode 删除
- 退出客户端: quit
- 帮助命令: help
- 创建子节点
子节点(或者称为子目录),必须一层层往下创建。
比如要创建 /a/b data 这样两层目录,必须先创建 /a 然后才能创建/a/b data - 10.
java方法集合
官方客户端 mvn
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.0</version>
</dependency>
connect - 连接到ZooKeeper集合
create- 创建znode
exists- 检查znode是否存在及其信息
getData - 从特定的znode获取数据
setData - 在特定的znode中设置数据
getChildren - 获取特定znode中的所有子节点
delete - 删除特定的znode及其所有子项
close - 关闭连接
注意事项
- zk的临时节点不能有子节点
- zk.getChildren和zk.exits中的注册的监听器有什么区别
Zookeeper机制的特点:
3.1. 一次性触发.数据发生改变时,一个watcher event会被发送到client,但是client只会收到一次这样的信息。若要一直被触发,可以每次在触发之后再重新注册。
3.2. 触发watcher create、delete、setData
3.3. watcher event异步发送 watcher 的通知事件从server发送到client是异步的,这就存在一个问题,不同的客户端和服务器之间通过socket进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于Zookeeper本身提供了ordering guarantee,即客户端监听事件后,才会感知它所监视znode发生了变化。
3.4. 数据监视 Zookeeper有数据监视和子数据监视 getdata() and exists() 设置数据监视,getchildren()设置了子节点监视
3.5. 注册watcher getData、exists、getChildren
第三方客户端ZKClient
关于zookeeper第三方客户端zkclient的使用说明
Zookeeper客户端提供了基本的操作,比如,创建会话、创建节点、读取节点、更新数据、删除节点和检查节点是否存在等。
Zookeeper API不足之处
zookeeper提供的基本操纵还是有一些不足之处。
在使用ZooKeeper的Java客户端时,经常需要处理几个问题:重复注册watcher、session失效重连、异常处理。
(1)Zookeeper的Watcher是一次性的,每次触发之后都需要重新进行注册;
(2)Session超时之后没有实现重连机制;
(3)异常处理繁琐,Zookeeper提供了很多异常,对于开发人员来说可能根本不知道该如何处理这些异常信息;
(4)只提供了简单的byte[]数组的接口,没有提供针对对象级别的序列化;
(5)创建节点时如果节点存在抛出异常,需要自行检查节点是否存在;
(6)删除节点无法实现级联删除;
zkClient主要做了两件事情:
一件是在session loss和session expire时自动创建新的ZooKeeper实例进行重连。
另一件是将一次性watcher包装为持久watcher。后者的具体做法是简单的在watcher回调中,重新读取数据的同时再注册相同的watcher实例。
组件设计
在ZKClient中,根据事件类型,分为了节点事件(数据事件)、子节点事件。对应的事件处理器则是IZKDataListener和IZKChildListener。另外加入了Session相关的事件和事件处理器。
zkclient接口介绍
zk监听子节点
subscribeChildChanges方法 订阅子节点变化
//对父节点添加监听子节点变化。
zkClient.subscribeChildChanges("/super", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("parentPath: " + parentPath);
System.out.println("currentChilds: " + currentChilds);
}
});
zkc.createPersistent("/super" + "/" + "c1", "c1内容");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c2", "c2内容");
从上面参数可以看到,每次/super中某一个节点修改(创建、删除),都只是拿到父节点即所有子节点。而不是修改哪个节点就拿到拿个节点。。
而且也不监听内容变化。
订阅内容变化
public class ZkClientWatcher2 {
/** zookeeper地址 */
static final String CONNECT_ADDR = "192.168.1.31:2181,192.168.1.32:2181,192.168.1.33:2181";
/** session超时时间 */
static final int SESSION_OUTTIME = 10000;//ms
public static void main(String[] args) throws Exception {
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
zkc.createPersistent("/super", "1234");
//对父节点添加监听子节点变化。
zkc.subscribeDataChanges("/super", new IZkDataListener() {
@Override
public void handleDataDeleted(String path) throws Exception {
System.out.println("删除的节点为:" + path);
}
@Override
public void handleDataChange(String path, Object data) throws Exception {
System.out.println("变更的节点为:" + path + ", 变更内容为:" + data);
}
});
Thread.sleep(3000);
zkc.writeData("/super", "456", -1);
Thread.sleep(1000);
zkc.delete("/super");
Thread.sleep(Integer.MAX_VALUE);
}
}
关于序列化问题
ZooKeeper中,会涉及到序列化、反序列化的操作有两种:getData、setData。在ZKClient中,分别用readData、writeData来替代了。
对于readData:先调用zookeeper的getData,然后进行使用ZKSerializer进行反序列化工作。
对于writeData:先使用ZKSerializer将对象序列化后,再调用zookeeper的setData。