使用ZooKeeper原生Java API进行客户端开发
6-1 建立客户端与zk服务端的连接
Java客户端连接zk服务端进行连接:
public class ZKConnect implements Watcher {
final static Logger log = LoggerFactory.getLogger(ZKConnect.class);
public static final String zkServerPath = "192.168.1.110:2181";
//如果是集群的话,链接地址直接用“,”隔开就行了;
// public static final String zkServerPath = "192.168.1.111:2181,192.168.1.111:2182,192.168.1.111:2183";
public static final Integer timeout = 5000;
public static void main(String[] args) throws Exception {
/**
* 客户端和zk服务端链接是一个异步的过程
* 当连接成功后后,客户端会收的一个watch通知
*
* 参数:
* connectString:连接服务器的ip字符串,
* 比如: "192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181"
* 可以是一个ip,也可以是多个ip,一个ip代表单机,多个ip代表集群
* 也可以在ip后加路径
* sessionTimeout:超时时间,心跳收不到了,那就超时
* watcher:通知事件,如果有对应的事件触发,则会收到一个通知;如果不需要,那就设置为null
* canBeReadOnly:可读,当这个物理机节点断开后,还是可以读到数据的,只是不能写,
* 此时数据被读取到的可能是旧数据,此处建议设置为false,不推荐使用
* sessionId:会话的id
* sessionPasswd:会话密码 当会话丢失后,可以依据 sessionId 和 sessionPasswd 重新获取会话
*/
ZooKeeper zk = new ZooKeeper(zkServerPath, timeout, new ZKConnect());
log.warn("客户端开始连接zookeeper服务器...");
log.warn("连接状态:{}", zk.getState());
new Thread().sleep(2000);
log.warn("连接状态:{}", zk.getState());
}
@Override
public void process(WatchedEvent event) {
log.warn("接受到watch通知:{}", event);
}
}
执行结果:
2018-11-30 17:05:46,643 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:41)] - [WARN] 客户端开始连接zookeeper服务器…
2018-11-30 17:05:46,658 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:42)] - [WARN] 连接状态:CONNECTING
2018-11-30 17:05:46,979 [main-EventThread] [com.imooc.zk.demo.ZKConnect.process(ZKConnect.java:51)] - [WARN] 接受到watch通知:WatchedEvent state:SyncConnected type:None path:null
2018-11-30 17:05:48,658 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:46)] - [WARN] 连接状态:CONNECTED
6-2 zk会话重连机制
/**
*
* @Title: ZKConnectDemo.java
* @Description: zookeeper 恢复之前的会话连接demo演示
*/
public class ZKConnectSessionWatcher implements Watcher {
final static Logger log = LoggerFactory.getLogger(ZKConnectSessionWatcher.class);
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper(zkServerPath, timeout, new ZKConnectSessionWatcher());
long sessionId = zk.getSessionId();
String ssid = "0x" + Long.toHexString(sessionId);
System.out.println(ssid);
byte[] sessionPassword = zk.getSessionPasswd();
log.warn("客户端开始连接zookeeper服务器...");
log.warn("连接状态:{}", zk.getState());
new Thread().sleep(1000);
log.warn("连接状态:{}", zk.getState());
new Thread().sleep(200);
// 开始会话重连
log.warn("开始会话重连...");
ZooKeeper zkSession = new ZooKeeper(zkServerPath,
timeout,
new ZKConnectSessionWatcher(),
sessionId,
sessionPassword);
log.warn("重新连接状态zkSession:{}", zkSession.getState());
new Thread().sleep(1000);
log.warn("重新连接状态zkSession:{}", zkSession.getState());
}
@Override
public void process(WatchedEvent event) {
log.warn("接受到watch通知:{}", event);
}
}
最主要的就是下面的这几行代码:获取sessionId,session的密码:
long sessionId = zk.getSessionId();
byte[] sessionPassword = zk.getSessionPasswd();
这个就是开始进行重连:
ZooKeeper zkSession = new ZooKeeper(zkServerPath, timeout, new ZKConnectSessionWatcher(), sessionId, sessionPassword);
这个就是运行结果:
2018-11-30 17:29:09,845 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:41)] - [WARN] 客户端开始连接zookeeper服务器…
2018-11-30 17:29:09,878 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:42)] - [WARN] 连接状态:CONNECTING
2018-11-30 17:29:09,947 [main-EventThread] [com.imooc.zk.demo.ZKConnect.process(ZKConnect.java:51)] - [WARN] 接受到watch通知:WatchedEvent state:SyncConnected type:None path:null
2018-11-30 17:29:11,879 [main] [com.imooc.zk.demo.ZKConnect.main(ZKConnect.java:46)] - [WARN] 连接状态:CONNECTED
我们通过四字命令查看当前的会话数为零:
6-3 同步异步创建zk节点
/**
*
* @Title: ZKConnectDemo.java
* @Description: zookeeper 操作demo演示
*/
public class ZKNodeOperator implements Watcher {
private ZooKeeper zookeeper = null;
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
public ZKNodeOperator() {}
public ZKNodeOperator(String connectString) {
try {
zookeeper = new ZooKeeper(connectString, timeout, new ZKNodeOperator());
} catch (IOException e) {
e.printStackTrace();
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
/**
*
* @Title: ZKOperatorDemo.java
* @Description: 创建zk节点
*/
public void createZKNode(String path, byte[] data, List<ACL> acls) {
String result = "";
try {
/**
* 同步或者异步创建节点,都不支持子节点的递归创建,异步有一个callback函数
* 参数:
* path:创建的路径
* data:存储的数据的byte[]
* acl:控制权限策略
* Ids.OPEN_ACL_UNSAFE --> world:anyone:cdrwa
* CREATOR_ALL_ACL --> auth:user:password:cdrwa
* createMode:节点类型, 是一个枚举
* PERSISTENT:持久节点
* PERSISTENT_SEQUENTIAL:持久顺序节点
* EPHEMERAL:临时节点
* EPHEMERAL_SEQUENTIAL:临时顺序节点
*/
result = zookeeper.create(path, data, acls, CreateMode.PERSISTENT);
// String ctx = "{'create':'success'}";
// zookeeper.create(path, data, acls, CreateMode.PERSISTENT, new CreateCallBack(), ctx);
System.out.println("创建节点:\t" + result + "\t成功...");
new Thread().sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
ZKNodeOperator zkServer = new ZKNodeOperator(zkServerPath);
// 创建zk节点
// zkServer.createZKNode("/testnode", "testnode".getBytes(), Ids.OPEN_ACL_UNSAFE);
/**
* 参数:
* path:节点路径
* data:数据
* version:数据状态
*/
// Stat status = zkServer.getZookeeper().setData("/testnode", "xyz".getBytes(), 2);
// System.out.println(status.getVersion());
/**
* 参数:
* path:节点路径
* version:数据状态
*/
zkServer.createZKNode("/test-delete-node", "123".getBytes(), Ids.OPEN_ACL_UNSAFE);
// zkServer.getZookeeper().delete("/test-delete-node", 2);
String ctx = "{'delete':'success'}";
zkServer.getZookeeper().delete("/test-delete-node", 0, new DeleteCallBack(), ctx);
Thread.sleep(2000);
}
public ZooKeeper getZookeeper() {
return zookeeper;
}
public void setZookeeper(ZooKeeper zookeeper) {
this.zookeeper = zookeeper;
}
@Override
public void process(WatchedEvent event) {
}
}
执行结果:
创建节点: /test-delete-node 成功…
删除节点/test-delete-node
{‘delete’:‘success’}
6-4 修改zk节点数据
/**
- 参数:
- path:节点路径
- data:数据
- version:数据状态
*/
Stat status = zkServer.getZookeeper().setData("/testnode", “xyz”.getBytes(), 2);
System.out.println(status.getVersion());
6-5 同步异步删除zk节点
/**
- 参数:
- path:节点路径
- version:数据状态
*/
zkServer.createZKNode("/test-delete-node", “123”.getBytes(), Ids.OPEN_ACL_UNSAFE);
zkServer.getZookeeper().delete("/test-delete-node", 2);
我们一定要注意版本号的问题;
当我们需要异步的调用的时候,那我们就要这样来做:
我们在操作的时候,一定要注意版本号的问题;
6-6 CountDownLatch的介绍
这个时候,就是一个阻塞的状态:
6-7 CountDownLatch代码示例
DangerCenter类:
/**
* 抽象类,用于演示 危险品化工车监控中心 统一检查
*/
public abstract class DangerCenter implements Runnable {
private CountDownLatch countDown; // 计数器
private String station; // 调度站
private boolean ok; // 调度站针对当前自己的站点进行检查,是否检查ok的标志
public DangerCenter(CountDownLatch countDown, String station) {
this.countDown = countDown;
this.station = station;
this.ok = false;
}
@Override
public void run() {
try {
check();
ok = true;
} catch (Exception e) {
e.printStackTrace();
ok = false;
} finally {
if (countDown != null) {
countDown.countDown();
}
}
}
/**
* 检查危化品车
* 蒸罐
* 汽油
* 轮胎
* gps
* ...
*/
public abstract void check();
public CountDownLatch getCountDown() {
return countDown;
}
public void setCountDown(CountDownLatch countDown) {
this.countDown = countDown;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public boolean isOk() {
return ok;
}
public void setOk(boolean ok) {
this.ok = ok;
}
}
下面有三个子类:
public class StationBeijingIMooc extends DangerCenter {
public StationBeijingIMooc(CountDownLatch countDown) {
super(countDown, "北京慕课调度站");
}
@Override
public void check() {
System.out.println("正在检查 [" + this.getStation() + "]...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("检查 [" + this.getStation() + "] 完毕,可以发车~");
}
}
public class StationJiangsuSanling extends DangerCenter {
public StationJiangsuSanling(CountDownLatch countDown) {
super(countDown, "江苏三林调度站");
}
@Override
public void check() {
System.out.println("正在检查 [" + this.getStation() + "]...");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("检查 [" + this.getStation() + "] 完毕,可以发车~");
}
}
public class StationShandongChangchuan extends DangerCenter {
public StationShandongChangchuan(CountDownLatch countDown) {
super(countDown, "山东长川调度站");
}
@Override
public void check() {
System.out.println("正在检查 [" + this.getStation() + "]...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("检查 [" + this.getStation() + "] 完毕,可以发车~");
}
}
6-8 获取zk节点数据
/**
*
* @Description: zookeeper 获取节点数据的demo演示
*/
public class ZKGetNodeData implements Watcher {
private ZooKeeper zookeeper = null;
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
private static Stat stat = new Stat();
public ZKGetNodeData() {}
public ZKGetNodeData(String connectString) {
try {
zookeeper = new ZooKeeper(connectString, timeout, new ZKGetNodeData());
} catch (IOException e) {
e.printStackTrace();
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
private static CountDownLatch countDown = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
ZKGetNodeData zkServer = new ZKGetNodeData(zkServerPath);
/**
* 参数:
* path:节点路径
* watch:true或者false,注册一个watch事件
* stat:状态
*/
byte[] resByte = zkServer.getZookeeper().getData("/imooc", true, stat);
String result = new String(resByte);
System.out.println("当前值:" + result);
countDown.await();
}
@Override
public void process(WatchedEvent event) {
try {
if(event.getType() == EventType.NodeDataChanged){
ZKGetNodeData zkServer = new ZKGetNodeData(zkServerPath);
byte[] resByte = zkServer.getZookeeper().getData("/imooc", false, stat);
String result = new String(resByte);
System.out.println("更改后的值:" + result);
System.out.println("版本号变化dversion:" + stat.getVersion());
countDown.countDown();
} else if(event.getType() == EventType.NodeCreated) {
} else if(event.getType() == EventType.NodeChildrenChanged) {
} else if(event.getType() == EventType.NodeDeleted) {
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public ZooKeeper getZookeeper() {
return zookeeper;
}
public void setZookeeper(ZooKeeper zookeeper) {
this.zookeeper = zookeeper;
}
}
6-9 获取zk子节点列表
/**
* @Description: zookeeper 获取子节点数据的demo演示
*/
public class ZKGetChildrenList implements Watcher {
private ZooKeeper zookeeper = null;
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
public ZKGetChildrenList() {}
public ZKGetChildrenList(String connectString) {
try {
zookeeper = new ZooKeeper(connectString, timeout, new ZKGetChildrenList());
} catch (IOException e) {
e.printStackTrace();
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
private static CountDownLatch countDown = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
ZKGetChildrenList zkServer = new ZKGetChildrenList(zkServerPath);
/**
* 参数:
* path:父节点路径
* watch:true或者false,注册一个watch事件
*/
// List<String> strChildList = zkServer.getZookeeper().getChildren("/imooc", true);
// for (String s : strChildList) {
// System.out.println(s);
// }
// 异步调用
String ctx = "{'callback':'ChildrenCallback'}";
// zkServer.getZookeeper().getChildren("/imooc", true, new ChildrenCallBack(), ctx);
zkServer.getZookeeper().getChildren("/imooc", true, new Children2CallBack(), ctx);
countDown.await();
}
@Override
public void process(WatchedEvent event) {
try {
if(event.getType()==EventType.NodeChildrenChanged){
System.out.println("NodeChildrenChanged");
ZKGetChildrenList zkServer = new ZKGetChildrenList(zkServerPath);
List<String> strChildList = zkServer.getZookeeper().getChildren(event.getPath(), false);
for (String s : strChildList) {
System.out.println(s);
}
countDown.countDown();
} else if(event.getType() == EventType.NodeCreated) {
System.out.println("NodeCreated");
} else if(event.getType() == EventType.NodeDataChanged) {
System.out.println("NodeDataChanged");
} else if(event.getType() == EventType.NodeDeleted) {
System.out.println("NodeDeleted");
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public ZooKeeper getZookeeper() {
return zookeeper;
}
public void setZookeeper(ZooKeeper zookeeper) {
this.zookeeper = zookeeper;
}
}
6-10 判断zk节点是否存在
/**
* @Description: zookeeper 判断阶段是否存在demo
*/
public class ZKNodeExist implements Watcher {
private ZooKeeper zookeeper = null;
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
public ZKNodeExist() {}
public ZKNodeExist(String connectString) {
try {
zookeeper = new ZooKeeper(connectString, timeout, new ZKNodeExist());
} catch (IOException e) {
e.printStackTrace();
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
private static CountDownLatch countDown = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
ZKNodeExist zkServer = new ZKNodeExist(zkServerPath);
/**
* 参数:
* path:节点路径
* watch:watch
*/
Stat stat = zkServer.getZookeeper().exists("/imooc-fake", true);
if (stat != null) {
System.out.println("查询的节点版本为dataVersion:" + stat.getVersion());
} else {
System.out.println("该节点不存在...");
}
countDown.await();
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == EventType.NodeCreated) {
System.out.println("节点创建");
countDown.countDown();
} else if (event.getType() == EventType.NodeDataChanged) {
System.out.println("节点数据改变");
countDown.countDown();
} else if (event.getType() == EventType.NodeDeleted) {
System.out.println("节点删除");
countDown.countDown();
}
}
public ZooKeeper getZookeeper() {
return zookeeper;
}
public void setZookeeper(ZooKeeper zookeeper) {
this.zookeeper = zookeeper;
}
}
6-11 acl - 默认匿名权限
public class ZKNodeAcl implements Watcher {
private ZooKeeper zookeeper = null;
public static final String zkServerPath = "192.168.1.110:2181";
public static final Integer timeout = 5000;
public ZKNodeAcl() {}
public ZKNodeAcl(String connectString) {
try {
zookeeper = new ZooKeeper(connectString, timeout, new ZKNodeAcl());
} catch (IOException e) {
e.printStackTrace();
if (zookeeper != null) {
try {
zookeeper.close();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
public void createZKNode(String path, byte[] data, List<ACL> acls) {
String result = "";
try {
/**
* 同步或者异步创建节点,都不支持子节点的递归创建,异步有一个callback函数
* 参数:
* path:创建的路径
* data:存储的数据的byte[]
* acl:控制权限策略
* Ids.OPEN_ACL_UNSAFE --> world:anyone:cdrwa
* CREATOR_ALL_ACL --> auth:user:password:cdrwa
* createMode:节点类型, 是一个枚举
* PERSISTENT:持久节点
* PERSISTENT_SEQUENTIAL:持久顺序节点
* EPHEMERAL:临时节点
* EPHEMERAL_SEQUENTIAL:临时顺序节点
*/
result = zookeeper.create(path, data, acls, CreateMode.PERSISTENT);
System.out.println("创建节点:\t" + result + "\t成功...");
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
ZKNodeAcl zkServer = new ZKNodeAcl(zkServerPath);
/**
* ====================== 创建node start ======================
*/
// acl 任何人都可以访问
// zkServer.createZKNode("/aclimooc", "test".getBytes(), Ids.OPEN_ACL_UNSAFE);
// 自定义用户认证访问
// List<ACL> acls = new ArrayList<ACL>();
// Id imooc1 = new Id("digest", AclUtils.getDigestUserPwd("imooc1:123456"));
// Id imooc2 = new Id("digest", AclUtils.getDigestUserPwd("imooc2:123456"));
// acls.add(new ACL(Perms.ALL, imooc1));
// acls.add(new ACL(Perms.READ, imooc2));
// acls.add(new ACL(Perms.DELETE | Perms.CREATE, imooc2));
// zkServer.createZKNode("/aclimooc/testdigest", "testdigest".getBytes(), acls);
// 注册过的用户必须通过addAuthInfo才能操作节点,参考命令行 addauth
// zkServer.getZookeeper().addAuthInfo("digest", "imooc1:123456".getBytes());
// zkServer.createZKNode("/aclimooc/testdigest/childtest", "childtest".getBytes(), Ids.CREATOR_ALL_ACL);
// Stat stat = new Stat();
// byte[] data = zkServer.getZookeeper().getData("/aclimooc/testdigest", false, stat);
// System.out.println(new String(data));
// zkServer.getZookeeper().setData("/aclimooc/testdigest", "now".getBytes(), 1);
// ip方式的acl
// List<ACL> aclsIP = new ArrayList<ACL>();
// Id ipId1 = new Id("ip", "192.168.1.6");
// aclsIP.add(new ACL(Perms.ALL, ipId1));
// zkServer.createZKNode("/aclimooc/iptest6", "iptest".getBytes(), aclsIP);
// 验证ip是否有权限
zkServer.getZookeeper().setData("/aclimooc/iptest6", "now".getBytes(), 1);
Stat stat = new Stat();
byte[] data = zkServer.getZookeeper().getData("/aclimooc/iptest6", false, stat);
System.out.println(new String(data));
System.out.println(stat.getVersion());
}
public ZooKeeper getZookeeper() {
return zookeeper;
}
public void setZookeeper(ZooKeeper zookeeper) {
this.zookeeper = zookeeper;
}
@Override
public void process(WatchedEvent event) {
}
}
6-12 acl -自定义用户权限
/**
* ====================== 创建node start ======================
*/
// acl 任何人都可以访问
// zkServer.createZKNode("/aclimooc", "test".getBytes(), Ids.OPEN_ACL_UNSAFE);
// 自定义用户认证访问
// List<ACL> acls = new ArrayList<ACL>();
// Id imooc1 = new Id("digest", AclUtils.getDigestUserPwd("imooc1:123456"));
// Id imooc2 = new Id("digest", AclUtils.getDigestUserPwd("imooc2:123456"));
// acls.add(new ACL(Perms.ALL, imooc1));
// acls.add(new ACL(Perms.READ, imooc2));
// acls.add(new ACL(Perms.DELETE | Perms.CREATE, imooc2));
// zkServer.createZKNode("/aclimooc/testdigest", "testdigest".getBytes(), acls);
// 注册过的用户必须通过addAuthInfo才能操作节点,参考命令行 addauth
// zkServer.getZookeeper().addAuthInfo("digest", "imooc1:123456".getBytes());
// zkServer.createZKNode("/aclimooc/testdigest/childtest", "childtest".getBytes(), Ids.CREATOR_ALL_ACL);
// Stat stat = new Stat();
// byte[] data = zkServer.getZookeeper().getData("/aclimooc/testdigest", false, stat);
// System.out.println(new String(data));
// zkServer.getZookeeper().setData("/aclimooc/testdigest", "now".getBytes(), 1);
// ip方式的acl
// List<ACL> aclsIP = new ArrayList<ACL>();
// Id ipId1 = new Id("ip", "192.168.1.6");
// aclsIP.add(new ACL(Perms.ALL, ipId1));
// zkServer.createZKNode("/aclimooc/iptest6", "iptest".getBytes(), aclsIP);
// 验证ip是否有权限
zkServer.getZookeeper().setData("/aclimooc/iptest6", "now".getBytes(), 1);
Stat stat = new Stat();
byte[] data = zkServer.getZookeeper().getData("/aclimooc/iptest6", false, stat);
System.out.println(new String(data));
System.out.println(stat.getVersion());
6-13 acl - ip权限
// ip方式的acl
// List<ACL> aclsIP = new ArrayList<ACL>();
// Id ipId1 = new Id("ip", "192.168.1.6");
// aclsIP.add(new ACL(Perms.ALL, ipId1));
// zkServer.createZKNode("/aclimooc/iptest6", "iptest".getBytes(), aclsIP);
// 验证ip是否有权限
zkServer.getZookeeper().setData("/aclimooc/iptest6", "now".getBytes(), 1);
Stat stat = new Stat();
byte[] data = zkServer.getZookeeper().getData("/aclimooc/iptest6", false, stat);
System.out.println(new String(data));
System.out.println(stat.getVersion());