zookeeper学习记录-06 Zookeeper JavaAPI操作

来源:互联网 发布:mac下安装配置redis4 编辑:程序博客网 时间:2024/05/21 14:41

新建一个maven项目

引入依赖jar包

pom.xml引入依赖jar包,实际上还需要sla4j和log4j,但是maven会自动帮忙我们引入这里只需要引入Zookeeper的即可

<dependency>      <groupId>org.apache.zookeeper</groupId>      <artifactId>zookeeper</artifactId>      <version>3.4.6</version></dependency>

新建一个类 - 测试连接Zookeeper服务器

import java.io.IOException;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            connCountDownLatch.countDown();        }    }    public static void main(String[] args) {        try {            ZooKeeper zooKeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample());            System.out.println(zooKeeper.getState());            connCountDownLatch.await();            System.out.println("Zookeeper session established");        } catch (IOException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

这里定义一个CountDownLatch ,在main方法中处于等待状态,当Zookeeper客户端连接上服务器之后解除阻塞,最终输出结果

CONNECTINGReceive watched event : WatchedEvent state:SyncConnected type:None path:nullZookeeper session established

Zookeeper构造说明:

这里写图片描述

在Zookeeper客户端与服务端建立连接是一个异步的过程,也就是说代码Zookeeper实例化之后马上返回,并没有真正的连接上了服务器端,所以代码中加上了CountDownLatch 来进行阻塞,当连接成功之后解除阻塞,打印最后一段话

创建节点

创建节点中两种方式,同步、异步.
参数说明:
这里写图片描述

同步

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_Create_API_Sync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            connCountDownLatch.countDown();        }    }    public static void main(String[] args) throws Exception {        ZooKeeper zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_Create_API_Sync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        String path1 = zookeeper.create("/zk-test-PERSISTENT-", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            System.out.println("Success create znode: " + path1);    }}

输出结果如下:可以看到

CONNECTINGReceive watched event : WatchedEvent state:SyncConnected type:None path:nullSuccess create znode: /zk-test-PERSISTENT-

异步

异步方式于同步方式的区别在于节点的创建过程(包括网络通信和服务端的节点创建过程)是异步的,在同步接口调用过程中,开发者需要关注接口抛出异常的可能,但是在异步接口中,接口本身不会抛出异常,所有异常都会在回调函数中通过Result Code来体现。

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.AsyncCallback;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_Create_API_ASync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            connCountDownLatch.countDown();        }    }    public static void main(String[] args) throws Exception {        ZooKeeper zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_Create_API_ASync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        zookeeper.create("/zk-test-ephemeral-", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,                new IStringCallback(), "I am context. ");        Thread.sleep(Integer.MAX_VALUE);    }    static class IStringCallback implements AsyncCallback.StringCallback{        @Override        public void processResult(int rc, String path, Object ctx, String name) {            System.out.println("Create path result: [" + rc + ", " + path + ", " + ctx + ", real path name: " + name);        }    }}

输出结果如下:

CONNECTINGReceive watched event : WatchedEvent state:SyncConnected type:None path:nullCreate path result: [-110, /zk-test-ephemeral-, I am context. , real path name: null

异步回调参数说明:
这里写图片描述

删除节点

删除节点提供了两个方法,分别是同步和异步.
这里写图片描述

参数说明:
这里写图片描述

同步

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_DELETE_API_Sync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            connCountDownLatch.countDown();        }    }    public static void main(String[] args) throws Exception {        ZooKeeper zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_DELETE_API_Sync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        zookeeper.delete("/zk-test-ephemeral-", 0);    }}

异步

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.AsyncCallback;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_DELETE_API_ASync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            connCountDownLatch.countDown();        }    }    public static void main(String[] args) throws Exception {        ZooKeeper zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_DELETE_API_ASync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        zookeeper.create("/zk123", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        zookeeper.delete("/zk123", 0 , new IVoidCallBack() , "test-delete async");        Thread.sleep(Integer.MAX_VALUE);    }    static class IVoidCallBack implements AsyncCallback.VoidCallback{        @Override        public void processResult(int rc, String path, Object ctx) {            System.out.println("rc : " + rc + " , path : " + path + " ctx : " + ctx.toString());        }    }}

输出如下:

CONNECTINGReceive watched event : WatchedEvent state:SyncConnected type:None path:nullrc : 0 , path : /zk123 ctx : test-delete async

子节点读取

这里写图片描述

参数说明

这里写图片描述
这里写图片描述

同步

import java.util.List;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_Children_API_Sync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    private static ZooKeeper zookeeper = null;    private static String path = "/zk01";    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            if(event.getType() == EventType.None && null == event.getPath()){                connCountDownLatch.countDown();            }else if(event.getType() == EventType.NodeChildrenChanged){                try {                    System.out.println("child change  reget childs : " + zookeeper.getChildren(path, true));                } catch (KeeperException e) {                    e.printStackTrace();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) throws Exception {        zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_Children_API_Sync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        zookeeper.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        zookeeper.create(path + "/c1", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        List<String> childs = zookeeper.getChildren(path, true);        System.out.println(childs);        zookeeper.create(path + "/c2", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        Thread.sleep(Integer.MAX_VALUE);    }}

输出结果:

CONNECTINGReceive watched event : WatchedEvent state:SyncConnected type:None path:null[c1]Receive watched event : WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zk01child change  reget childs : [c1, c2]

需要注意的是Watcher通知是一次性的,即一旦触发一次通知后,该Watcher就失效了,因此客户端需要反复注册Watcher,即程序中在process里面又注册了Watcher

异步

import java.util.List;import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.AsyncCallback;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.data.Stat;public class ZK_Sample_Children_API_ASync implements Watcher{    private static CountDownLatch connCountDownLatch = new CountDownLatch(1);    private static ZooKeeper zookeeper = null;    private static String path = "/zk02";    @Override    public void process(WatchedEvent event) {        System.out.println("Receive watched event : " + event);        if(KeeperState.SyncConnected == event.getState()){            if(event.getType() == EventType.None && null == event.getPath()){                connCountDownLatch.countDown();            }else if(event.getType() == EventType.NodeChildrenChanged){                try {                    System.out.println("child change  reget childs : " + zookeeper.getChildren(path, true));                } catch (KeeperException e) {                    e.printStackTrace();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) throws Exception {        zookeeper = new ZooKeeper("192.168.7.151:2181", 5000, new ZK_Sample_Children_API_ASync());        System.out.println(zookeeper.getState());        connCountDownLatch.await();        zookeeper.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        zookeeper.create(path + "/c1", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        zookeeper.getChildren(path, true,new IChildren2Callback(),"获取子节点");        zookeeper.create(path + "/c2", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        Thread.sleep(Integer.MAX_VALUE);    }    static class IChildren2Callback implements AsyncCallback.Children2Callback {        public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {            System.out.println("Get Children znode result: [response code: " + rc + ", path: " + path + ", ctx: "                    + ctx + ", children list: " + children + ", stat: " + stat);        }    }}

数据获取

Zookeeper API 提供了四个接口来获取数据,同样分同步,异步.

这里写图片描述

参数说明
这里写图片描述

更新数据

Zookeeper API 提供了两个接口来更新数据,同样分同步,异步.

这里写图片描述

参数说明
这里写图片描述

在更新数据时,setData方法存在一个version参数,其用于指定节点的数据版本,表明本次更新操作是针对指定的数据版本进行的,但是,在getData方法中,并没有提供根据指定数据版本来获取数据的接口,那么,这里为何要指定数据更新版本呢,这里方便理解,可以等效于CAS(compare and swap),对于值V,每次更新之前都会比较其值是否是预期值A,只有符合预期,才会将V原子化地更新到新值B。Zookeeper的setData接口中的version参数可以对应预期值,表明是针对哪个数据版本进行更新,假如一个客户端试图进行更新操作,它会携带上次获取到的version值进行更新,而如果这段时间内,Zookeeper服务器上该节点的数据已经被其他客户端更新,那么其数据版本也会相应更新,而客户端携带的version将无法匹配,无法更新成功,因此可以有效地避免分布式更新的并发问题。

检测节点是否存在

Zookeeper API 提供了四个接口来检测节点是否存在,同样分同步,异步.

这里写图片描述

参数说明

这里写图片描述

在调用接口时注册Watcher的话,还可以对节点是否存在进行监听,一旦节点被创建、被删除、数据更新,都会通知客户端

同步

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_Exist_API_Sync implements Watcher {    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);    private static ZooKeeper zk;    public static void main(String[] args) throws Exception {        String path = "/zk-book";        zk = new ZooKeeper("192.168.7.151:2181", 5000, //                new ZK_Sample_Exist_API_Sync());        connectedSemaphore.await();        zk.exists(path, true);        zk.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        zk.setData(path, "123".getBytes(), -1);        zk.create(path + "/c1", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);        System.out.println("success create znode: " + path + "/c1");        zk.delete(path + "/c1", -1);        zk.delete(path, -1);        Thread.sleep(Integer.MAX_VALUE);    }    public void process(WatchedEvent event) {        try {            if (KeeperState.SyncConnected == event.getState()) {                if (EventType.None == event.getType() && null == event.getPath()) {                    connectedSemaphore.countDown();                } else if (EventType.NodeCreated == event.getType()) {                    System.out.println("success create znode: " + event.getPath());                    zk.exists(event.getPath(), true);                } else if (EventType.NodeDeleted == event.getType()) {                    System.out.println("success delete znode: " + event.getPath());                    zk.exists(event.getPath(), true);                } else if (EventType.NodeDataChanged == event.getType()) {                    System.out.println("data changed of znode: " + event.getPath());                    zk.exists(event.getPath(), true);                }            }        } catch (Exception e) {        }    }}

输出结果

success create znode: /zk-bookdata changed of znode: /zk-booksuccess create znode: /zk-book/c1success delete znode: /zk-book
  • 无论节点是否存在,都可以通过exists接口注册Watcher。

  • 注册的Watcher,对节点创建、删除、数据更新事件进行监听。

  • 对于指定节点的子节点的各种变化,不会通知客户端。

异步

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.AsyncCallback;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.data.Stat;public class ZK_Sample_Exist_API_ASync implements Watcher {    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);    private static ZooKeeper zk;    public static void main(String[] args) throws Exception {        String path = "/zk-book";        zk = new ZooKeeper("192.168.7.151:2181", 5000,                new ZK_Sample_Exist_API_ASync());        connectedSemaphore.await();        zk.exists(path, true, new IIStatCallback(), null);        zk.create(path, "".getBytes(), Ids.OPEN_ACL_UNSAFE,                CreateMode.PERSISTENT);        zk.setData(path, "123".getBytes(), -1);        zk.create(path + "/c1", "".getBytes(), Ids.OPEN_ACL_UNSAFE,                CreateMode.PERSISTENT);        System.out.println("success create znode: " + path + "/c1");        zk.delete(path + "/c1", -1);        zk.delete(path, -1);        Thread.sleep(Integer.MAX_VALUE);    }    public void process(WatchedEvent event) {        try {            if (KeeperState.SyncConnected == event.getState()) {                if (EventType.None == event.getType()                        && null == event.getPath()) {                    connectedSemaphore.countDown();                } else if (EventType.NodeCreated == event.getType()) {                    System.out.println("success create znode: "                            + event.getPath());                    zk.exists(event.getPath(), true, new IIStatCallback(), null);                } else if (EventType.NodeDeleted == event.getType()) {                    System.out.println("success delete znode: "                            + event.getPath());                    zk.exists(event.getPath(), true, new IIStatCallback(), null);                } else if (EventType.NodeDataChanged == event.getType()) {                    System.out.println("data changed of znode: "                            + event.getPath());                    zk.exists(event.getPath(), true, new IIStatCallback(), null);                }            }        } catch (Exception e) {        }    }    static class IIStatCallback implements AsyncCallback.StatCallback {        public void processResult(int rc, String path, Object ctx, Stat stat) {            System.out.println("rc: " + rc + ", path: " + path + ", stat: " + stat);        }    }}

输出结果

rc: -101, path: /zk-book, stat: nullsuccess create znode: /zk-bookrc: 0, path: /zk-book, stat: 12884901993,12884901993,1508491896292,1508491896292,0,0,0,0,0,0,12884901993data changed of znode: /zk-bookrc: 0, path: /zk-book, stat: 12884901993,12884901994,1508491896292,1508491896313,1,0,0,0,3,0,12884901993success create znode: /zk-book/c1success delete znode: /zk-bookrc: -101, path: /zk-book, stat: null

当节点不存在时,其rc(ResultCode)为-101。

权限认证

在实际过程中,可能是一个Zookeeper集群,有多个项目,多个服务共同使用,避免错误操作,数据读取权限,就需要进行认证了。
Zookeeper api 提供了权限认证
这里写图片描述

参数说明:

这里写图片描述

认证失败示例

import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_ACL_API_AUTH_FAIL{    public static void main(String[] args) throws Exception {        String path = "/zk-book";        ZooKeeper zookeeper1 = new ZooKeeper("192.168.7.151:2181", 5000, null);        zookeeper1.addAuthInfo("digest", "foo:true".getBytes());        zookeeper1.create(path, "init".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);        System.out.println("success create znode: " + path);        ZooKeeper zookeeper2 = new ZooKeeper("192.168.7.151:2181", 5000, null);        zookeeper2.getData(path, false, null);    }}

输出结果

success create znode: /zk-bookException in thread "main" org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /zk-book    at org.apache.zookeeper.KeeperException.create(KeeperException.java:113)    at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)    at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1155)    at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1184)    at com.jx.zk.first.ZK_Sample_ACL_API_AUTH_FAIL.main(ZK_Sample_ACL_API_AUTH_FAIL.java:16)

认证通过

import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.ZooDefs.Ids;import org.apache.zookeeper.ZooKeeper;public class ZK_Sample_ACL_API_AUTH_SUCC{    public static void main(String[] args) throws Exception {        String path = "/zk-book";        ZooKeeper zookeeper1 = new ZooKeeper("192.168.7.151:2181", 5000, null);        zookeeper1.addAuthInfo("digest", "foo:true".getBytes());        zookeeper1.create(path, "init".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);        System.out.println("success create znode: " + path);        ZooKeeper zookeeper2 = new ZooKeeper("192.168.7.151:2181", 5000, null);        zookeeper2.addAuthInfo("digest", "foo:true".getBytes());        byte[] bt = zookeeper2.getData(path, false, null);        System.out.println(new String(bt));    }}

输出结果

success create znode: /zk-bookinit

不同的客户端之间带上一样的认证信息即可.