zookeeper的客戶端應用
阿新 • • 發佈:2018-11-02
什麼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!"); } }