Zookeeper之java api詳解

znode是Zookeeper集合的核心組件,Zookeeper api提供了一小組方法使用Zookeeper集合來操縱znode的所有細節。這裏沒有涉及watch相關的api,另外介紹。

客戶端應該遵循以下步驟,以保證與Zookeeper服務器進行清晰乾淨的交互。

  • 連接到Zookeeper服務器。Zookeeper服務器爲客戶端分配會話ID。
  • 定期向服務器發送心跳。否則Zookeeper服務器將過期會話ID。客戶端需要重新連接。
  • 只要會話ID處於活躍狀態,就可以操作znode。
  • 所以任務完成後,斷開與Zookeeper服務器的連接。如果客戶端長期不活動,則Zookeeper服務器將自動斷開客戶端。

需要導入依賴

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

demo代碼,每種操作都要同步異步兩種模式。

public class ZookeeperDemo implements Watcher{
    private ZooKeeper zooKeeper;


    //路徑前綴
    private static final String PATH_PREFIX = "/javaapi";

    //相當於發令槍,會阻塞線程,待得Count變爲0時,就喚醒線程。
    CountDownLatch latch = new CountDownLatch(1);

    @Override
    public void process(WatchedEvent watchedEvent) {
        if (watchedEvent.getState().equals(Event.KeeperState.SyncConnected)){
            //如果客戶端已經連接到Zookeeper服務器,就會觸發SyncConnected事件,進入這裏。
            //發令器減1  變爲0  被該發令器阻塞的線程將被喚醒
            latch.countDown();
            System.out.println("已連接到客戶端");
        }
        if (watchedEvent.getState().equals(Event.KeeperState.Expired)){
            //latch.countDown();
            System.out.println("連接超時");
        }
    }

    @Before
    public void init(){
        try {
            //創建一個Zookeeper客戶端並連接到服務器,因爲連接過程是異步執行的,所以要配合CountDownLatch保證在發送請求前客戶端
            //與服務器已經建立了連接
            //第一個參數:要連接到Zookeeper服務器地址。 第二個參數,session超時,單位毫秒。 第三個參數,爲該客戶端註冊監聽。
            zooKeeper = new ZooKeeper("192.168.18.130:2181",5000,this);
            //阻塞線程。CountDownLatch減爲0時就會喚醒線程
            latch.await();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @After
    public void destroy(){
        try {
            //關閉連接
            zooKeeper.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步創建節點
     */
    @Test
    public void testAddNodeSync(){
        try {
            //第一個參數  創建節點的路徑
            //第二個參數  節點的數據 ,是一個字節數組
            //第三個參數  節點的ACL list列表   ZooDefs.Ids.READ_ACL_UNSAFE代表 world:anyone:adcwr  ,後面會詳解。
            //第四個參數   節點的類型
            //返回值是創建的節點的路徑

            //創建持久化節點
            String result = zooKeeper.create(PATH_PREFIX + "/PersistentNode","PersistentNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println(result);
            //創建持久化有序節點
            zooKeeper.create(PATH_PREFIX + "/PersistentSeqNode","PersistentSeqNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT);
            //創建臨時節點
            zooKeeper.create(PATH_PREFIX + "/EPHEMERALNode","EPHEMERALNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.EPHEMERAL);
            //創建臨時有序節點
            zooKeeper.create(PATH_PREFIX + "/EPHEMERALSeqNode","EPHEMERALSeqNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 異步創建節點
     */
    @Test
    public void testAddNodeAsync(){
        //第一個參數  創建節點的路徑
        //第二個參數  節點的數據 ,是一個字節數組
        //第三個參數  節點的ACL   ZooDefs.Ids.READ_ACL_UNSAFE代表 world:anyone:adcwr  ,後面會詳解。
        //第四個參數   節點的類型
        //第五個參數   節點創建完成(無論成功還是失敗)的回調。
        //上下文ctx
        zooKeeper.create(PATH_PREFIX + "/asyncNode", "asyncNode".getBytes(), ZooDefs.Ids.READ_ACL_UNSAFE,
                CreateMode.PERSISTENT, new AsyncCallback.StringCallback() {
                    @Override
                    public void processResult(int rc, String path, Object ctx, String name) {
                        //結果標誌,爲0時代表節點創建成功
                        System.out.println(rc);
                        //節點的路徑
                        System.out.println(path);
                        //上下文參數,就是該create方法傳入的最後一個參數
                        System.out.println(ctx);
                        //節點的路徑。當創建節點失敗時,爲null。
                        System.out.println(name);

                    }
                },"aa");
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    //創建節點時賦予特定的ACL
    @Test
    public void testCreateNodeWithACL(){
        //創建ACL訪問控制列表
        //第一個參數是權限 1代表 read 2 代表 write 4代表 create 8代表 delete  16代表 admin  相互組合用相加 比如1+2=3 是rw
        //第二個參數 Id對象代表授權模型和授權對象 ,構造函數第一個是授權模型 world、ip、auth、digest  第二個參數是授權對象

        //world:anyone:r
        ACL aclWorld = new ACL(1,new Id("world","anyone"));
        //digest:admin:0uek/hZ/V9fgiM35b0Z2226acMQ=:adcwr
        ACL aclDigest= new ACL(1+2+4+8+16,new Id("digest","admin:0uek/hZ/V9fgiM35b0Z2226acMQ="));
        //ip:192.168.18.128:rw
        ACL aclIP = new ACL(1+2,new Id("ip","192.168.18.128"));
        //把ACL添加到acl列表中,這個就是創建節點要傳遞的參數
        List<ACL> acls = new ArrayList<>();

        acls.add(aclWorld);
        acls.add(aclDigest);
        acls.add(aclIP);
        try {
            zooKeeper.create(PATH_PREFIX + "/nodeACL","nodeACL".getBytes(),
                    acls,CreateMode.PERSISTENT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //同步修改節點數據
    @Test
    public void testSetNode(){
        try {
            //第一個參數  修改的節點路徑
            //第二個參數  修改的節點數據
            //數據的版本號 ,用於實現樂觀鎖的,如果此版本號與Zookeeper服務器中的該節點數據的版本號不一樣,就會修改失敗
            //返回的是修改後節點的元信息,用Stat類封裝,與命令 stat path 返回的一致。-1表示該參數不參與修改節點
            Stat stat = zooKeeper.setData(PATH_PREFIX + "/nodeSetData","nodeSetData".getBytes(),-1);
            System.out.println(stat.getVersion());
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //修改節點ACL
    @Test
    public void testSetNodeACL(){
        ACL aclWorld = new ACL(1,new Id("world","anyone"));
        //digest:admin:0uek/hZ/V9fgiM35b0Z2226acMQ=:adcwr
        ACL aclDigest= new ACL(1+2+4+8+16,new Id("digest","admin:0uek/hZ/V9fgiM35b0Z2226acMQ="));
        //ip:192.168.18.128:rw
        ACL aclIP = new ACL(1+2,new Id("ip","192.168.18.128"));
        List<ACL> acls = new ArrayList<>();
        acls.add(aclWorld);
        acls.add(aclDigest);
        acls.add(aclIP);
        try {
            //第一個參數,節點路徑
            //第二個參數:要修改的ACL
            //第三個參數aVersion  -1則表示該參數不參與
            zooKeeper.setACL(PATH_PREFIX + "/setACL",acls,-1);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //刪除節點
    @Test
    public void testDeleteNode(){

        try {
            //第一個參數:要刪除的節點路徑
            //第二個參數數據版本,-1表示不參與。
            zooKeeper.delete(PATH_PREFIX + "/nodeDelete",-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    //查看節點數據
    @Test
    public void getData(){
        Stat stat = new Stat();
        try {
            //第一個參數是節點路徑
            //第二個參數是是否註冊監聽,true的話就會註冊創建Zookeeper客戶端時傳入的監聽,第三個是傳入stat對象,會把獲取到的節點元信息賦值到該對象中。
            //返回值是節點數據的字節數組
            byte[] result = zooKeeper.getData(PATH_PREFIX + "/nodeSetData",false,stat);
            System.out.println(new String(result,"utf-8"));
            System.out.println(stat.getVersion());
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //獲取子節點
    @Test
    public void getChildrenNode(){
        try {
            //第一個參數:節點路徑
            //第二個參數:是否註冊監聽
            //返回值 節點路徑列表list。
            List<String> children = zooKeeper.getChildren(PATH_PREFIX, false);
            System.out.println(children);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //查看節點是否存在
    @Test
    public void testNodeExist(){
        try {
            //參數1:節點路徑
            //第二個參數:是否註冊監聽
            //返回值 stat對象,節點的元數據,如果節點不存在就返回null
            Stat exists = zooKeeper.exists("/888", false);
            System.out.println(exists);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章