1. 程式人生 > >zookeeper的客戶端應用

zookeeper的客戶端應用

什麼zookeeper?

  ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要元件。它是一個為分散式應用提供一致性服務的軟體,提供的功能包括:配置維護、域名服務、分散式同步、組服務等。

ZooKeeper的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。 ZooKeeper包含一個簡單的原語集, 提供Java和C的介面。

ZooKeeper程式碼版本中,提供了分散式獨享鎖、選舉、佇列的介面,程式碼在zookeeper-3.4.3\src\recipes。其中分佈鎖和佇列有java和C兩個版本,選舉只有Java版本。

zookeeper的原理:

  ZooKeeper是以Fast Paxos演算法為基礎的,Paxos演算法存在活鎖的問題,即當有多個proposer交錯提交時,有可能互相排斥導致沒有一個proposer能提交成功,而Fast Paxos作了一些優化,通過選舉產生一個leader (領導者),只有leader才能提交proposer,具體演算法可見Fast Paxos。因此,要想弄懂ZooKeeper首先得對Fast Paxos有所瞭解。 [3]   ZooKeeper的基本運轉流程: 1、選舉Leader。 2、同步資料。 3、選舉Leader過程中演算法有很多,但要達到的選舉標準是一致的。 4、Leader要具有最高的執行ID,類似root許可權。

5、叢集中大多數的機器得到響應並接受選出的Leader。

為什麼zookeeper適合作為註冊中心?

  Zookeeper的資料模型很簡單,有一系列被稱為ZNode的資料節點組成,與傳統的磁碟檔案系統不同的是,zk將全量資料儲存在記憶體中,可謂是高效能,而且支援叢集,可謂高可用,另外支援事件監聽。這些特點決定了zk特別適合作為註冊中心(資料釋出/訂閱)。

下面介紹兩種zookeeper客戶端的實現,第一種使用zookeeper自帶的原生客戶端,第二種使用Apache Curator封裝後的zookeeper客戶端,第一種接近zookeeper底層的原始碼,它底層也是用了這些方法,使用者使用起來較繁瑣,推薦使用第二種,Apache Curator封裝後簡化了使用者的使用。

 

maven引入:

 

<!--zookeeper自帶的原生客戶端依賴引入-->
    <dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.6</version>
    </dependency>

<!--Apache Curator封裝後的zookeeper客戶端使用依賴引入-->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>2.9.0</version>
    </dependency>

 

 

 

 

先介紹第一種zookeeper自帶的原生客戶端:

 

package com.wenbing.zookeeper;

import org.apache.zookeeper.*;

//原生zookeeper客戶端使用
public class zookeeperSelfTest {

    private static final String connectString = "192.168.159.128:2181,192.168.159.133:2181,192.168.159.134:2181";
    private static final int sessionTimeout = 3000;


    public static void main(String[] args) throws Exception {
//        建立一個與伺服器的連線,需要(伺服器的ip+埠)(session過期時間)(Watcher監聽註冊)
        ZooKeeper zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            //                監聽所有被觸發的事件
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("監聽來了:" + watchedEvent.toString());
            }
        });
        System.out.println("OK!");
//        建立一個目錄節點
        /**
         * CreateMode:
         *      PERSISTENT(持續的,相對於EPHEMERAL,不會隨著client的斷開而消失
         *      PERSISTENT_SEQUENTIAL(持久的且帶順序的)
         *      EPHEMERAL (短暫的,生命週期依賴於client session)
         *      EPHEMERAL_SEQUENTIAL  (短暫的,帶順序的)
         */
        if (zk.exists("/test01", false) == null) {
            zk.create("/test01", "goodboy".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
//        建立一個子目錄節點
        zk.create("/test01/test01", "goodgirl".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println(zk.getData("/test01", false,null).toString());
//        取出子目錄節點列表
        System.out.println(zk.getChildren("/test01", true));
//        建立另一個子目錄節點
        zk.create("/test01/test02", "goodgirl2".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println(zk.getChildren("/test01", true));
//      修改子目錄節點資料
        zk.setData("/test01/test01", "goodboy/boy02".getBytes(), -1);
        byte[] datas = zk.getData("/test01/test01", false, null);
        String str = new String(datas, "UTF-8");
        System.out.println(str);

//        刪除整個子目錄 -1代表version版本號,-1是刪除所有版本
        zk.delete("/test01/test01", -1);
        zk.delete("/test01/test02", -1);
        zk.delete("/test01", -1);
        System.out.println(str);
        Thread.sleep(15000);
        zk.close();
        System.out.println("OK!結束!");
    }

}

 

Apache Curator封裝的zookeeper客戶端使用:

package com.wenbing.zookeeper;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooDefs;

import java.util.List;

//Apache Curator封裝的zookeeperk客戶端使用
public class CuratorTest {

//    psvm快捷鍵main方法生成
    public static void main(String[] args) throws Exception {
        CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.159.128:2181", new RetryNTimes(10, 5000));
//        連線
        client.start();
//        獲取子節點,順便監控子節點
        List<String> children = client.getChildren().usingWatcher(new CuratorWatcher() {
            @Override
            public void process(WatchedEvent watchedEvent) throws Exception {
                System.out.println("監控:"+watchedEvent);
            }
        }).forPath("/");
        System.out.println(children);
//        建立節點
        String result = client.create().withMode(CreateMode.PERSISTENT).withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).forPath("/test", "Data".getBytes());
        System.out.println(result);
//        設定節點資料
        client.setData().forPath("/test", "111".getBytes());
        client.setData().forPath("/test", "222".getBytes());
//        刪除節點
        System.out.println(client.checkExists().forPath("/test"));
//        client.delete().withVersion(-1).forPath("/test");
        System.out.println(client.checkExists().forPath("/test"));
        Thread thread = new Thread(new Runnable(){
            @Override
            public void run(){
            }
        });
        thread.sleep(Long.MAX_VALUE);
        client.close();
        System.out.println("OK!");
    }

}