Zookeeper技術內幕

1 重要理論

1.1 數(shù)據(jù)模型znode

01.png

zk 數(shù)據(jù)存儲結構與標準的 Unix 文件系統(tǒng)非常相似图甜,都是在根節(jié)點下掛很多子節(jié)點碍粥。zk 中沒有引入傳統(tǒng)文件系統(tǒng)中目錄與文件的概念,而是使用了稱為znode 的數(shù)據(jù)節(jié)點概念黑毅。znode 是 zk 中數(shù)據(jù)的最小單元嚼摩,每個 znode 上都可以保存數(shù)據(jù),同時還可以掛載子節(jié)點矿瘦,形成一個樹形化命名空間枕面。

(1)節(jié)點類型

  • 持久節(jié)點:其會一直保存在 zk 中,直到將其刪除為止缚去。
  • 持久順序節(jié)點:
  • 臨時節(jié)點:其與創(chuàng)建它的會話是綁定的潮秘,會話消失,臨時節(jié)點消失
  • 臨時順序節(jié)點

(2)節(jié)點狀態(tài)

  • cZxid:Created Zxid易结,表示當前 znode 被創(chuàng)建時的事務 ID
  • ctime:Created Time枕荞,表示當前 znode 被創(chuàng)建的時間
  • mZxid:Modified Zxid柜候,表示當前 znode 最后一次被修改時的事務 ID
  • mtime:Modified Time,表示當前 znode 最后一次被修改時的時間
  • pZxid:表示當前 znode 的子節(jié)點列表最后一次被修改時的事務 ID躏精。注意渣刷,只能是其子節(jié)點列表變更了才會引起 pZxid 的變更,子節(jié)點內容的修改不會影響 pZxid矗烛。
  • cversion:Children Version辅柴,表示子節(jié)點的版本號。該版本號用于充當樂觀鎖瞭吃。
  • dataVersion:表示當前 znode 數(shù)據(jù)的版本號碌嘀。該版本號用于充當樂觀鎖。
  • aclVersion:表示當前 znode 的權限 ACL 的版本號歪架。該版本號用于充當樂觀鎖股冗。
  • ephemeralOwner:若當前 znode 是持久節(jié)點,則其值為 0和蚪;若為臨時節(jié)點魁瞪,則其值為創(chuàng)建該節(jié)點的會話的 SessionID。當會話消失后惠呼,會根據(jù) SessionID 來查找與該會話相關的臨時節(jié)點進行刪除。
  • dataLength:當前 znode 中存放的數(shù)據(jù)的長度峦耘。
  • numChildren:當前 znode 所包含的子節(jié)點的個數(shù)剔蹋。

1.2 ACL

(1)ACL 簡介

ACL 全稱為 Access Control List(訪問控制列表),是一種細粒度的權限管理策略辅髓,可以針對任意用戶與組進行細粒度的權限控制泣崩。zk 利用 ACL 控制znode 節(jié)點的訪問權限,如節(jié)點數(shù)據(jù)讀寫洛口、節(jié)點創(chuàng)建矫付、節(jié)點刪除、讀取子節(jié)點列表第焰、設置節(jié)點權限等买优。
擴展知識:UGO(User,Group挺举,Other)杀赢,是粗粒度權限管理策略。

(2)zk 的 ACL 維度

Unix/Linux 系統(tǒng)的 ACL 分為兩個維度:組與權限湘纵。而 Zookeeper 的 ACL 分為三個維度: 授權策略 scheme脂崔、授權對象 id、用戶權限 permission梧喷。
擴展知識:大多數(shù) Unix 已經支持 ACL砌左,Linux 從 2.6 版本開始也支持 ACL 了

  • Unix/Linux 中的 ACL:子目錄/子文件默認繼承父目錄的 ACL
  • zk 中的 ACL:子 znode 不會繼承父 znode 的 ACL

A脖咐、授權策略 scheme

授權策略用于確定權限驗證過程中使用的檢驗策略(簡單地說就是,通過什么來驗證權限汇歹,即一個用戶要訪問某個 znode屁擅,如何驗證其身份),在 zk 中最常用的有四種策略秤朗。

  • IP
  • digest:使用用戶名與密碼進行驗證
  • world:不驗證
  • super:

B煤蹭、 授權對象 id

授權對象指的是權限賦予的用戶。不同的授權策略具有不同類型的授權對象取视。下面是各個授權模式對應的授權對象 id硝皂。

  • ip
  • digest
  • world:anyone
  • Super

C、 權限 Permission

權限指的是通過驗證的用戶可以對znode 執(zhí)行的操作作谭。共有五種權限稽物,不過 zk 支持自定義權限。

  • c:create折欠,允許授權對象在當前節(jié)點下創(chuàng)建子節(jié)點
  • d:delete
  • r:read
  • w:write
  • a:acl

1.3 Watcher 機制

zk 通過 Watcher 機制實現(xiàn)了發(fā)布/訂閱模式贝或。

(1)watcher 工作原理

02.png

(2)watcher 事件

對于同一個事件類型,在不同的通知狀態(tài)中代表的含義是不同的锐秦。


屏幕截圖 2021-03-16 134351.png

(3)watcher 特性

zk 的watcher 機制具有以下幾個特性咪奖。

  • 一次性:zk 的watcher 機制不適合監(jiān)聽變化非常頻繁的場景
  • 串行性:
  • 輕量級:

1.4 會話

會話是 zk 中最重要的概念之一,客戶端與服務端之間的任何交互操作都與會話相關酱床。
ZooKeeper 客戶端啟動時羊赵,首先會與 zk 服務器建立一個 TCP 長連接。連接一旦建立扇谣,客戶端會話的生命周期也就開始了昧捷。

(1)會話狀態(tài)

常見的會話狀態(tài)有三種:

A、CONNECTING(重要)

連接中罐寨∶一樱客戶端要創(chuàng)建連接,首先會在客戶端創(chuàng)建一個zk 對象鸯绿“掀疲客戶端會采用輪詢方式逐個獲取服務器列表中的 zk 的 IP 進行連接嘗試,直到連接成功瓶蝴。注意幔烛,在輪詢之前,首先會將服務器列表打散囊蓝,然后再進行輪詢饿悬。

B、 CONNECTED

已連接聚霜。

C狡恬、 CLOSED

已關閉珠叔。若出現(xiàn)會話超時、權限驗證失敗或客戶端主動退出等情況弟劲,客戶端狀態(tài)就變?yōu)榱?CLOSED祷安,注意,此時客戶端的 zk 對象就消失了兔乞。

(2)會話連接超時管理

當客戶端向 zk 發(fā)出連接請求后汇鞭,是如何知道是否連接成功的呢?當 zk 接收到某客戶端會話連接后庸追,其會向該客戶端發(fā)送連接成功 ACK霍骄。當客戶端接收到 ACK 后,就知道自己已經與 zk 建立了連接淡溯。
若 zk 沒有收到連接請求读整,或客戶端沒有收到 zk 發(fā)送的 ACK 怎么辦呢?客戶端就需要進行等待咱娶,直到發(fā)生會話連接超時米间。然后再進行下一次連接嘗試。當然膘侮,嘗試一直連接不上怎么辦屈糊?這就依賴于連接時設置的超時重試策略了。
會話連接超時是由客戶端維護的琼了。

(3)會話空閑超時管理(重要)

zk 為每一個客戶端都維護著空閑超時管理另玖。一旦空閑超時,服務端就會認為該客戶端已丟失表伦,其會將該會話的 SessionId 從服務端清除。這也就是為什么客戶端在空閑時需要定時向服務端發(fā)送心跳慷丽,就是為了維護這個會話長連接的蹦哼。服務器是通過空閑超時管理來判斷會話是否發(fā)生中斷的。
會話空閑超時管理是由服務端維護的要糊。其采用了一種特殊的方式——分桶策略纲熏。

A、基本概念

分桶策略是指锄俄,將空閑超時時間相近的會話放到同一個桶中來進行管理局劲,以減少管理的復雜度。在檢查超時時奶赠,只需要檢查桶中剩下的會話即可鱼填,因為在該桶的時間范圍內沒有超時的會話已經被移出了桶,而桶中存在的會話就是超時的會話毅戈。
zk 對于會話空閑的超時管理并非是精確的管理苹丸,即并非是一超時馬上就執(zhí)行相關的超時操作愤惰。


03.png

B、 分桶依據(jù)

現(xiàn)要在計算當前的會話需要存放到哪個會話桶中進行管理赘理。分桶的計算依據(jù)為:

ExpirationTime= CurrentTime + SessionTimeout
BucketTime = (ExpirationTime/ExpirationInterval + 1) * ExpirationInterval

從以上公式可知宦言,一個桶的大小為 ExpirationInterval 時間。只要 ExpirationTime 落入到同一個桶中商模,系統(tǒng)就會對其中的會話超時進行統(tǒng)一管理奠旺。

(4)會話連接事件

客戶端與服務端的長連接失效后,客戶端將進行重連施流。在重連過程中客戶端會產生三種會話連接事件:

  • 連接丟失
  • 會話轉移
  • 會話失效

2 客戶端命令

2.1 啟動客戶端

(1)連接本機 zk 服務器

04.png

(2)連接其它 zk 服務器

05.png

2.2 查看子節(jié)點-ls

查看根節(jié)點及/brokers 節(jié)點下所包含的所有子節(jié)點列表响疚。


06.png

2.3 創(chuàng)建節(jié)點-create

(1)創(chuàng)建永久節(jié)點

創(chuàng)建一個名稱為 china 的znode,其值為 999嫂沉。


07.png

(2)創(chuàng)建順序節(jié)點

在/china 節(jié)點下創(chuàng)建了順序子節(jié)點 beijing稽寒、shanghai、guangzhou趟章,它們的數(shù)據(jù)內容分別為 bj杏糙、sh、gz蚓土。


08.png

(3)創(chuàng)建臨時節(jié)點

臨時節(jié)點與持久節(jié)點的區(qū)別宏侍,在后面 get 命令中可以看到。


09.png

(4)創(chuàng)建臨時順序節(jié)點

10.png

2.4 獲取節(jié)點信息-get

(1)獲取持久節(jié)點數(shù)據(jù)

11.png

(2)獲取順序節(jié)點信息

12.png

(3)獲取臨時節(jié)點信息

13.png

2.5 更新節(jié)點數(shù)據(jù)內容-set

更新前:


14.png

更新:


15.png

16.png

2.6 刪除節(jié)點-delete

17.png

若要刪除具有子節(jié)點的節(jié)點蜀漆,會報錯谅河。


18.png

2.7 ACL 操作

(1)查看權限-getAcl

19.png

(2)設置權限

下面的命令是,首先增加了一個認證用戶 zs确丢,密碼為 123绷耍,然后為/china 節(jié)點指定只有
zs 用戶才可訪問該節(jié)點,而訪問權限為所有權限鲜侥。


20.png

3 可視化客戶端

zk 常見的可視化客戶端有兩個:ZooView 與 ZooInspector蛛砰。

3.1 ZooView

解壓后直接雙擊運行 startup.bat 即可根蟹。


21.png

3.2 ZooInspector

在解壓目錄的 build 目錄下進入 cmd 窗口,然后通過 jar 命令運行下面的 jar 包。


22.png

4 ZKClient 客戶端

4.1 簡介

ZkClient 是一個開源客戶端钧嘶,在 Zookeeper 原生API 接口的基礎上進行了包裝拗胜,更便于開發(fā)人員使用驯绎。內部實現(xiàn)了 Session 超時重連市埋,Watcher 反復注冊等功能。像 dubbo 等框架對其也進行了集成使用互墓。

4.2 API 介紹

以下 API 方法均是 ZkClient 類中的方法必尼。

(1)創(chuàng)建會話

ZkClient 中提供了九個構造器用于創(chuàng)建會話。


23.png

查看這些方法的源碼可以看到具體的參數(shù)名稱篡撵,這些參數(shù)的意義為:

參數(shù)名 意義
zkServers 指定zk 服務器列表胰伍,由英文狀態(tài)逗號分開的 host:port 字符串組成
connectionTimeout 設置連接創(chuàng)建超時時間齿诞,單位毫秒。在此時間內無法創(chuàng)建與zk 的連接骂租,則直接放棄連接祷杈,并拋出異常
sessionTimeout 設置會話超時時間,單位毫秒
zkSerializer 為會話指定序列化器渗饮。zk 節(jié)點內容僅支持字節(jié)數(shù)組(byte[])類型但汞, 且 zk 不負責序列化。在創(chuàng)建 zkClient 時需要指定所要使用的序列化器互站,例如 Hessian 或Kryo私蕾。默認使用 Java 自帶的序列化方式進行對象的序列化。當為會話指定了序列化器后胡桃,客戶端在進行讀寫操作時就會自動進行序列化與反序列化踩叭。
connection IZkConnection 接口對象,是對zk 原生 API 的最直接包裝翠胰,是和zk 最直接的交互層容贝,包含了增刪改查等一系列方法。該接口最常用的實現(xiàn)類是 zkClient 默認的實現(xiàn)類 ZkConnection之景,其可以完成絕大部分的業(yè)務需求斤富。
operationRetryTimeout 設置重試超時時間,單位毫秒

(2)創(chuàng)建節(jié)點

ZkClient 中提供了 15 個方法用于創(chuàng)建節(jié)點锻狗。


24.png

查看這些方法的源碼可以看到具體的參數(shù)名稱满力,這些參數(shù)的意義為:

參數(shù)名 意義
path 要創(chuàng)建的節(jié)點完整路徑
data 節(jié)點的初始數(shù)據(jù)內容,可以傳入 Object 類型及 null轻纪。zk 原生API中只允許向節(jié)點傳入 byte[]數(shù)據(jù)作為數(shù)據(jù)內容油额,但 zkClient 中具有自定義序列化器,所以可以傳入各種類型對象刻帚。
mode 節(jié)點類型潦嘶,CreateMode 枚舉常量,常用的有四種類型我擂。
?PERSISTENT:持久型
?PERSISTENT_SEQUENTIAL:持久順序型
?EPHEMERAL:臨時型
?EPHEMERAL_SEQUENTIAL:臨時順序型
acl 節(jié)點的 ACL 策略
callback 回調接口
context 執(zhí)行回調時可以使用的上下文對象
createParents 是否級遞歸創(chuàng)建節(jié)點。zk 原生 API 中要創(chuàng)建的節(jié)點路徑必須存在缓艳, 即要創(chuàng)建子節(jié)點校摩,父節(jié)點必須存在。但zkClient 解決了這個問題阶淘, 可以做遞歸節(jié)點創(chuàng)建衙吩。沒有父節(jié)點,可以先自動創(chuàng)建了父節(jié)點溪窒,然后再在其下創(chuàng)建子節(jié)點坤塞。

(3)刪除節(jié)點

ZkClient 中提供了 3 個方法用于創(chuàng)建節(jié)點冯勉。


25.png

查看這些方法的源碼可以看到具體的參數(shù)名稱,這些參數(shù)的意義為:

參數(shù)名 意義
path 要刪除的節(jié)點的完整路徑
version 要刪除的節(jié)點中包含的數(shù)據(jù)版本

(4)更新數(shù)據(jù)

ZkClient 中提供了 3 個方法用于修改節(jié)點數(shù)據(jù)內容摹芙。


26.png

查看這些方法的源碼可以看到具體的參數(shù)名稱灼狰,這些參數(shù)的意義為:

參數(shù)名 意義
path 要更新的節(jié)點的完整路徑
data 要采用的新的數(shù)據(jù)值
expectedVersion 數(shù)據(jù)更新后要采用的數(shù)據(jù)版本號

(5)檢測節(jié)點是否存在

ZkClient 中提供了 2 個方法用于判斷指定節(jié)點的存在性,但 public 方法就一個:只有一個參數(shù)的exists()方法浮禾。


27.png

查看這些方法的源碼可以看到具體的參數(shù)名稱交胚,這些參數(shù)的意義為:

參數(shù)名 意義
path 要判斷存在性節(jié)點的完整路徑
watch 要判斷存在性節(jié)點及其子孫節(jié)點是否具有 watcher 監(jiān)聽

(6)獲取節(jié)點數(shù)據(jù)內容

ZkClient 中提供了 4 個方法用于獲取節(jié)點數(shù)據(jù)內容,但 public 方法就三個盈电。


28.png

查看這些方法的源碼可以看到具體的參數(shù)名稱蝴簇,這些參數(shù)的意義為:

參數(shù)名 意義
path 要讀取數(shù)據(jù)內容的節(jié)點的完整路徑
watch 指定節(jié)點及其子孫節(jié)點是否具有 watcher 監(jiān)聽
returnNullIfPathNotExists 這是個 boolean 值。默認情況下若指定的節(jié)點不存在匆帚,則會拋出 KeeperException$NoNodeException 異常熬词。設置該值為 true,若指定節(jié)點不存在吸重,則直接返回 null 而不再拋出異常互拾。
stat 指定當前節(jié)點的狀態(tài)信息。不過晤锹,執(zhí)行過后該 stat 值會被最新獲取到的 stat 值給替換摩幔。

(7)獲取子節(jié)點列表

ZkClient 中提供了 2 個方法用于獲取節(jié)點的子節(jié)點列表,但 public 方法就一個:只有一個參數(shù)的 getChildren()方法鞭铆。


29.png

查看這些方法的源碼可以看到具體的參數(shù)名稱或衡,這些參數(shù)的意義為:

參數(shù)名 意義
path 要獲取子節(jié)點列表的節(jié)點的完整路徑
watch 要獲取子節(jié)點列表的節(jié)點及其子孫節(jié)點是否具有 watcher 監(jiān)聽

(8)watcher 注冊

ZkClient 采用 Listener 來實現(xiàn) Watcher 監(jiān)聽〕邓欤客戶端可以通過注冊相關監(jiān)聽器來實現(xiàn)對zk 服務端事件的訂閱封断。
可以通過 subscribeXxx()方法實現(xiàn) watcher 注冊,即相關事件訂閱舶担;通過 unsubscribeXxx()方法取消相關事件的訂閱坡疼。


30.png

查看這些方法的源碼可以看到具體的參數(shù)名稱,這些參數(shù)的意義為:

參數(shù)名 意義
path 要操作節(jié)點的完整路徑
watch 要判斷存在性節(jié)點及其子孫節(jié)點是否具有 watcher 監(jiān)聽
IZkChildListener 子節(jié)點數(shù)量變化監(jiān)聽器
IZkDataListener 數(shù)據(jù)內容變化監(jiān)聽器
IZkStateListener 客戶端與zk 的會話連接狀態(tài)變化監(jiān)聽器衣陶,可以監(jiān)聽新會話的創(chuàng)建柄瑰、會話創(chuàng)建出錯、連接狀態(tài)改變剪况。連接狀態(tài)是系統(tǒng)定義好的枚舉類型 Event.KeeperState 的常量

4.3 代碼演示

(1)創(chuàng)建工程

創(chuàng)建一個 Maven 的 Java 工程教沾,并導入以下依賴。


31.png

這里僅創(chuàng)建一個 ZkClient 的測試類即可译断。本例不適合使用 JUnit 測試授翻。


32.png

(2)代碼

public class ZKClientTest {
    // 指定 zk 集群 
    private static final String CLUSTER = "zkOS:2181";
    // 指定節(jié)點名稱 
    private static final String PATH = "/mylog";
    public static void main(String[] args) {
        // ---------------- 創(chuàng)建會話 -----------
        // 創(chuàng)建 zkClient
        ZkClient zkClient = new ZkClient(CLUSTER);
        // 為 zkClient 指定序列化器 
        zkClient.setZkSerializer(new SerializableSerializer()); 
        // ---------------- 創(chuàng)建節(jié)點 -----------
        // 指定創(chuàng)建持久節(jié)點 
        CreateMode mode = CreateMode.PERSISTENT;
        // 指定節(jié)點數(shù)據(jù)內容 
        String data = "first log";
        // 創(chuàng)建節(jié)點 
        String nodeName = zkClient.create(PATH, data, mode); 
        System.out.println("新創(chuàng)建的節(jié)點名稱為:" + nodeName);
        // ---------------- 獲取數(shù)據(jù)內容 -----------
        Object readData = zkClient.readData(PATH); 
        System.out.println("節(jié)點的數(shù)據(jù)內容為:" + readData);
        // ---------------- 注冊 watcher -----------
        zkClient.subscribeDataChanges(PATH, new IZkDataListener() { 
            @Override
            public void handleDataChange(String dataPath, Object data) throws Exception{
                System.out.print(" 節(jié) 點 " + dataPath); 
                System.out.println("的數(shù)據(jù)已經更新為了" + data);
            }
            @Override
            public void handleDataDeleted(String dataPath) throws Exception { 
                System.out.println(dataPath + "的數(shù)據(jù)內容被刪除");
            }
        });
        // ---------------- 更新數(shù)據(jù)內容 -----------
        zkClient.writeData(PATH, "second log"); 
        String updatedData = zkClient.readData(PATH);
        System.out.println("更新過的數(shù)據(jù)內容為:" + updatedData);

        // ---------------- 刪除節(jié)點 -----------
        zkClient.delete(PATH);

        // ---------------- 判斷節(jié)點存在性 -----------
        boolean isExists = zkClient.exists(PATH); 
        System.out.println(PATH + "節(jié)點仍存在嗎?" + isExists);
    }
}

5 Curator 客戶端

5.1 簡介

Curator 是Netflix 公司開源的一套 zk 客戶端框架,與 ZkClient 一樣堪唐,其也封裝了 zk 原生API巡语。其目前已經成為Apache 的頂級項目。同時淮菠,Curator 還提供了一套易用性男公、可讀性更強的 Fluent 風格的客戶端 API 框架。

5.2 API 介紹

這里主要以 Fluent 風格客戶端 API 為主進行介紹兜材。

(1)創(chuàng)建會話

A理澎、普通 API 創(chuàng)建 newClient()

在 CuratorFrameworkFactory 類中提供了兩個靜態(tài)方法用于完成會話的創(chuàng)建。


33.png

查看這些方法的源碼可以看到具體的參數(shù)名稱曙寡,這些參數(shù)的意義為:

參數(shù)名 意義
connectString 指定zk 服務器列表糠爬,由英文狀態(tài)逗號分開的 host:port 字符串組成
sessionTimeoutMs 設置會話超時時間,單位毫秒举庶,默認 60 秒
connectionTimeoutMs 設置連接超時時間执隧,單位毫秒,默認 15 秒
retryPolicy 重試策略户侥,內置有四種策略镀琉,分別由以下四個類的實例指定:ExponentialBackoffRetry、RetryNTimes蕊唐、RetryOneTime屋摔、RetryUntilElapsed

B、 Fluent 風格創(chuàng)建

34.png

(2)創(chuàng)建節(jié)點 create()

下面以滿足各種需求的舉例方式分別講解節(jié)點創(chuàng)建的方法替梨。
說明:下面所使用的 client 為前面所創(chuàng)建的Curator 客戶端實例钓试。

  • 創(chuàng)建一個節(jié)點,初始內容為空
    語句:client.create().forPath(path);
    說明:默認創(chuàng)建的是持久節(jié)點副瀑,數(shù)據(jù)內容為空弓熏。
  • 創(chuàng)建一個節(jié)點,附帶初始內容
    語句:client.create().forPath(path, “mydata”.getBytes());
    說明:Curator 在指定數(shù)據(jù)內容時糠睡,只能使用 byte[]作為方法參數(shù)挽鞠。
  • 創(chuàng)建一個臨時節(jié)點,初始內容為空
    語句:client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
    說明:CreateMode 為枚舉類型狈孔。
  • 創(chuàng)建一個臨時節(jié)點信认,并自動遞歸創(chuàng)建父節(jié)點
    語句:client.create().createingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);
    說明:若指定的節(jié)點多級父節(jié)點均不存在,則會自動創(chuàng)建均抽。

(3)刪除節(jié)點delete()

  • 刪除一個節(jié)點
    語句:client.delete().forPath(path);
    說明:只能將葉子節(jié)點刪除嫁赏,其父節(jié)點不會被刪除。
  • 刪除一個節(jié)點到忽,并遞歸刪除其所有子節(jié)點
    語句:client.delete().deletingChildrenIfNeeded().forPath(path);
    說明:該方法在使用時需謹慎橄教。

(4)更新數(shù)據(jù)setData()

  • 設置一個節(jié)點的數(shù)據(jù)內容
    語句:client.setData().forPath(path, newData);
    說明:該方法具有返回值,返回值為 Stat 狀態(tài)對象喘漏。

(5)檢測節(jié)點是否存在 checkExits()

  • 設置一個節(jié)點的數(shù)據(jù)內容
    語句:Stat stat = client.checkExists().forPath(path);
    說明:該方法具有返回值护蝶,返回值為 Stat 狀態(tài)對象。若 stat 為 null翩迈,說明該節(jié)點不存在持灰,否則說明節(jié)點是存在的。

(6)獲取節(jié)點數(shù)據(jù)內容getData()

  • 讀取一個節(jié)點的數(shù)據(jù)內容
    語句:byte[] data = client.getDate().forPath(path);
    說明:其返回值為byte[]數(shù)組负饲。

(7)獲取子節(jié)點列表 getChildren()

  • 讀取一個節(jié)點的所有子節(jié)點列表
    語句:List<String> childrenNames = client.getChildren().forPath(path);
    說明:其返回值為byte[]數(shù)組堤魁。

(8)watcher 注冊 usingWatcher()

curator 中綁定 watcher 的操作有三個:checkExists()、getData()返十、getChildren()妥泉。這三個方法的共性是,它們都是用于獲取的洞坑。這三個操作用于 watcher 注冊的方法是相同的盲链,都是usingWatcher()方法。


35.png

這兩個方法中的參數(shù) CuratorWatcher 與 Watcher 都為接口迟杂。這兩個接口中均包含一個process()方法刽沾,它們的區(qū)別是,CuratorWatcher 中的 process()方法能夠拋出異常排拷,這樣的話侧漓, 該異常就可以被記錄到日志中。

  • 監(jiān)聽節(jié)點的存在性變化
Stat stat = client.checkExists().usingWatcher((CuratorWatcher) event -> { System.out.println("節(jié)點存在性發(fā)生變化");}).forPath(path);
  • 監(jiān)聽節(jié)點的內容變化
byte[] data = client.getData().usingWatcher((CuratorWatcher) event -> { System.out.println("節(jié)點數(shù)據(jù)內容發(fā)生變化");}).forPath(path);
  • 監(jiān)聽節(jié)點子節(jié)點列表變化
List<String> sons = client.getChildren().usingWatcher((CuratorWatcher) event -> { System.out.println("節(jié)點的子節(jié)點列表發(fā)生變化");}).forPath(path);

5.3 代碼演示

(1)創(chuàng)建工程

創(chuàng)建一個 Maven 的 Java 工程监氢,并導入以下依賴布蔗。


36.png

(2)代碼

public class FluentTest {
    public static void main(String[] args) throws Exception {
        // ---------------- 創(chuàng)建會話 -----------
        // 創(chuàng)建重試策略對象:第 1 秒重試 1 次,最多重試 3 次 
        ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
        // 創(chuàng)建客戶端 
        CuratorFramework client = CuratorFrameworkFactory
                                    .builder()
                                    .connectString("zkOS:2181")
                                    .sessionTimeoutMs(15000)
                                    .connectionTimeoutMs(13000)
                                    .retryPolicy(retryPolicy)
                                    .namespace("logs")
                                    .build();
         // 開啟客戶端 
        client.start();

        // 指定要創(chuàng)建和操作的節(jié)點忙菠,注意何鸡,其是相對于/logs 節(jié)點的 
        String nodePath = "/host";

        // ---------------- 創(chuàng)建節(jié)點 -----------
        String nodeName = client.create().forPath(nodePath, "myhost".getBytes());
        System.out.println("新創(chuàng)建的節(jié)點名稱為:" + nodeName);

        // ---------------- 獲取數(shù)據(jù)內容并注冊 watcher -----------
        byte[] data = client.getData().usingWatcher(
            (CuratorWatcher) event -> 
            {System.out.println(event.getPath() + "數(shù)據(jù)內容發(fā)生變化");}
        ).forPath(nodePath);
        System.out.println("節(jié)點的數(shù)據(jù)內容為:" + new String(data));

        // ---------------- 更新數(shù)據(jù)內容 -----------
        client.setData().forPath(nodePath, "newhost".getBytes());
        // 獲取更新過的數(shù)據(jù)內容 
        byte[] newData = client.getData().forPath(nodePath); 
        System.out.println("更新過的數(shù)據(jù)內容為:" + new String(newData));

        // ---------------- 刪除節(jié)點 -----------
        client.delete().forPath(nodePath);

        // ---------------- 判斷節(jié)點存在性 -----------
        Stat stat = client.checkExists().forPath(nodePath);
        boolean isExists = true; 
        if(stat == null) {
            isExists = false;
        }
        System.out.println(nodePath + "節(jié)點仍存在嗎?" + isExists);
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末牛欢,一起剝皮案震驚了整個濱河市骡男,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌傍睹,老刑警劉巖隔盛,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拾稳,居然都是意外死亡吮炕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門访得,熙熙樓的掌柜王于貴愁眉苦臉地迎上來龙亲,“玉大人陕凹,你說我怎么就攤上這事■” “怎么了杜耙?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拂盯。 經常有香客問我佑女,道長,這世上最難降的妖魔是什么谈竿? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任团驱,我火速辦了婚禮,結果婚禮上空凸,老公的妹妹穿的比我還像新娘嚎花。我一直安慰自己,他們只是感情好呀洲,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布贩幻。 她就那樣靜靜地躺著,像睡著了一般两嘴。 火紅的嫁衣襯著肌膚如雪丛楚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天憔辫,我揣著相機與錄音趣些,去河邊找鬼。 笑死贰您,一個胖子當著我的面吹牛坏平,可吹牛的內容都是我干的。 我是一名探鬼主播锦亦,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼舶替,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了杠园?” 一聲冷哼從身側響起顾瞪,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抛蚁,沒想到半個月后陈醒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瞧甩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年钉跷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肚逸。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡爷辙,死狀恐怖彬坏,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情膝晾,我是刑警寧澤苍鲜,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站玷犹,受9級特大地震影響,放射性物質發(fā)生泄漏洒疚。R本人自食惡果不足惜歹颓,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望油湖。 院中可真熱鬧巍扛,春花似錦、人聲如沸乏德。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喊括。三九已至胧瓜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郑什,已是汗流浹背府喳。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蘑拯,地道東北人钝满。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像申窘,于是被迫代替她去往敵國和親弯蚜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內容