1 重要理論
1.1 數(shù)據(jù)模型znode
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 工作原理
(2)watcher 事件
對于同一個事件類型,在不同的通知狀態(tài)中代表的含義是不同的锐秦。
(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í)行相關的超時操作愤惰。
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 服務器
(2)連接其它 zk 服務器
2.2 查看子節(jié)點-ls
查看根節(jié)點及/brokers 節(jié)點下所包含的所有子節(jié)點列表响疚。
2.3 創(chuàng)建節(jié)點-create
(1)創(chuàng)建永久節(jié)點
創(chuàng)建一個名稱為 china 的znode,其值為 999嫂沉。
(2)創(chuàng)建順序節(jié)點
在/china 節(jié)點下創(chuàng)建了順序子節(jié)點 beijing稽寒、shanghai、guangzhou趟章,它們的數(shù)據(jù)內容分別為 bj杏糙、sh、gz蚓土。
(3)創(chuàng)建臨時節(jié)點
臨時節(jié)點與持久節(jié)點的區(qū)別宏侍,在后面 get 命令中可以看到。
(4)創(chuàng)建臨時順序節(jié)點
2.4 獲取節(jié)點信息-get
(1)獲取持久節(jié)點數(shù)據(jù)
(2)獲取順序節(jié)點信息
(3)獲取臨時節(jié)點信息
2.5 更新節(jié)點數(shù)據(jù)內容-set
更新前:
更新:
2.6 刪除節(jié)點-delete
若要刪除具有子節(jié)點的節(jié)點蜀漆,會報錯谅河。
2.7 ACL 操作
(1)查看權限-getAcl
(2)設置權限
下面的命令是,首先增加了一個認證用戶 zs确丢,密碼為 123绷耍,然后為/china 節(jié)點指定只有
zs 用戶才可訪問該節(jié)點,而訪問權限為所有權限鲜侥。
3 可視化客戶端
zk 常見的可視化客戶端有兩個:ZooView 與 ZooInspector蛛砰。
3.1 ZooView
解壓后直接雙擊運行 startup.bat 即可根蟹。
3.2 ZooInspector
在解壓目錄的 build 目錄下進入 cmd 窗口,然后通過 jar 命令運行下面的 jar 包。
4 ZKClient 客戶端
4.1 簡介
ZkClient 是一個開源客戶端钧嘶,在 Zookeeper 原生API 接口的基礎上進行了包裝拗胜,更便于開發(fā)人員使用驯绎。內部實現(xiàn)了 Session 超時重連市埋,Watcher 反復注冊等功能。像 dubbo 等框架對其也進行了集成使用互墓。
4.2 API 介紹
以下 API 方法均是 ZkClient 類中的方法必尼。
(1)創(chuàng)建會話
ZkClient 中提供了九個構造器用于創(chuàng)建會話。
查看這些方法的源碼可以看到具體的參數(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é)點锻狗。
查看這些方法的源碼可以看到具體的參數(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é)點冯勉。
查看這些方法的源碼可以看到具體的參數(shù)名稱,這些參數(shù)的意義為:
參數(shù)名 | 意義 |
---|---|
path | 要刪除的節(jié)點的完整路徑 |
version | 要刪除的節(jié)點中包含的數(shù)據(jù)版本 |
(4)更新數(shù)據(jù)
ZkClient 中提供了 3 個方法用于修改節(jié)點數(shù)據(jù)內容摹芙。
查看這些方法的源碼可以看到具體的參數(shù)名稱灼狰,這些參數(shù)的意義為:
參數(shù)名 | 意義 |
---|---|
path | 要更新的節(jié)點的完整路徑 |
data | 要采用的新的數(shù)據(jù)值 |
expectedVersion | 數(shù)據(jù)更新后要采用的數(shù)據(jù)版本號 |
(5)檢測節(jié)點是否存在
ZkClient 中提供了 2 個方法用于判斷指定節(jié)點的存在性,但 public 方法就一個:只有一個參數(shù)的exists()方法浮禾。
查看這些方法的源碼可以看到具體的參數(shù)名稱交胚,這些參數(shù)的意義為:
參數(shù)名 | 意義 |
---|---|
path | 要判斷存在性節(jié)點的完整路徑 |
watch | 要判斷存在性節(jié)點及其子孫節(jié)點是否具有 watcher 監(jiān)聽 |
(6)獲取節(jié)點數(shù)據(jù)內容
ZkClient 中提供了 4 個方法用于獲取節(jié)點數(shù)據(jù)內容,但 public 方法就三個盈电。
查看這些方法的源碼可以看到具體的參數(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()方法鞭铆。
查看這些方法的源碼可以看到具體的參數(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()方法取消相關事件的訂閱坡疼。
查看這些方法的源碼可以看到具體的參數(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 工程教沾,并導入以下依賴。
這里僅創(chuàng)建一個 ZkClient 的測試類即可译断。本例不適合使用 JUnit 測試授翻。
(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)建。
查看這些方法的源碼可以看到具體的參數(shù)名稱曙寡,這些參數(shù)的意義為:
參數(shù)名 | 意義 |
---|---|
connectString | 指定zk 服務器列表糠爬,由英文狀態(tài)逗號分開的 host:port 字符串組成 |
sessionTimeoutMs | 設置會話超時時間,單位毫秒举庶,默認 60 秒 |
connectionTimeoutMs | 設置連接超時時間执隧,單位毫秒,默認 15 秒 |
retryPolicy | 重試策略户侥,內置有四種策略镀琉,分別由以下四個類的實例指定:ExponentialBackoffRetry、RetryNTimes蕊唐、RetryOneTime屋摔、RetryUntilElapsed |
B、 Fluent 風格創(chuàng)建
(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()方法。
這兩個方法中的參數(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 工程监氢,并導入以下依賴布蔗。
(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);
}
}