1. 程式人生 > >坐下坐下,基本操作(ZooKeeper 操作篇)

坐下坐下,基本操作(ZooKeeper 操作篇)

![](https://img2020.cnblogs.com/blog/759200/202101/759200-20210124161622816-1605238160.png)

本文作者:HelloGitHub-老荀

Hi,這裡是 HelloGitHub 推出的 HelloZooKeeper 系列,**免費開源、有趣、入門級的 ZooKeeper 教程**,面向有程式設計基礎的新手。 > ZooKeeper 是 Apache 軟體基金會的一個軟體專案,它為大型分散式計算提供開源的分散式配置服務、同步服務和命名註冊。 ZooKeeper 曾經是 Hadoop 的一個子專案,但現在是一個頂級獨立的開源專案。 ZK 在實際開發工作中經常會用見到,算的上是吃飯的傢伙了,那可得玩透、用的趁手,要不怎麼進階和升職加薪呢?來和 HelloGitHub 一起學起來吧~ 本系列教程是**從零開始**講解 ZooKeeper,內容從**最基礎的安裝使用到背後原理和原始碼的講解**,整個系列希望通過有趣文字、詼諧的氣氛中讓 ZK 的知識“鑽”進你聰明的大腦。本教程是開放式:開源、協作,所以不管你是新手還是老司機,我們都希望你可以**加入到本教程的貢獻中,一起讓這個教程變得更好**: - 新手:參與修改文中的錯字、病句、拼寫、排版等問題 - 使用者:參與到內容的討論和問題解答、幫助其他人的事情 - 老司機:參與到文章的編寫中,讓你的名字出現在作者一欄 > 專案地址:https://github.com/HelloGitHub-Team/HelloZooKeeper 今天我們會講解下,如何使用 Java 程式碼客戶端去操作 ZK。 ## 一、基本操作 ### 1.1 馬果果的新規定 老規矩,在開始實戰之前呢,我還是講一個小故事(故事中的人物,純屬虛構,請勿對號入座,如有雷同,純屬巧合)。 **馬果果**自從擔任了辦事處的負責人後,每天那是忙的不可開交,村民有事都來找他,他的小本子上已經密密麻麻記了一大堆: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145815843-1963392023.png) 特別是**雞太美**,儼然已經成為了日更 UP 主,每天的頻繁更新讓**馬果果**倍感力不從心,他想,如果再這樣毫無章法的記下去,不但以後自己會越來越累,等自己退休後,別人來交接也會無從下手,那還不得在背後說我管理不當,對著我指指點點。要晚節不保啊,到時候怕不是要給全村人民謝罪。 ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145824893-1640334831.png) 於是辦事處出臺了新的規定,每次過來登記的村民必須對自己要登記的事務進行分類,而**馬果果**則根據這些分類去進行記錄,所以**馬果果**的筆記(以下簡稱:小紅本)就變成了這樣: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145832532-66023983.png) 但是執行了規定一段時間以後,以**雞太美**和**馬小云**為首的村民代表又向**馬果果**提出了:“我們都是老熟人了,每次來都得自報家門,能不能做點便民措施?你這辦事處的宗旨難道不就是服務咱人民群眾的嗎?” **馬果果**聽完也覺得很有道理,於是給每一個老熟人都建立了一個標籤。比如以後**雞太美**過來建立的記錄,都直接放到**雞太美**的標籤下,這樣**雞太美**只需要關心自己具體想要記哪些東西就行了,所以筆記本最後變成了這樣: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145839353-883604097.png) 而對於需要接收到通知到村民也是一樣,**馬果果**會在需要通知的事務旁備註下,比如**雞太美**的頭號粉絲**坤坤**,對**雞太美**的跳舞視訊十分感興趣,所以在**雞太美**的跳舞事務旁備註下: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145847258-1012461458.png) 然後拿出另一本本子(以下簡稱:小黃本)把需要通知誰給記下來: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145854217-317844268.png) 隨著時間推移**雞太美**的人氣與日俱增,現在連**馬小云**,**東東**都成了她的粉絲,紛紛都要關注她的更新: ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145901893-140572790.png) 所以現在**馬果果**當記錄完小紅本後,會看看當前的事務是不是有別人訂閱了通知,如果有的話,會再拿出小黃本去找到對應需要通知的村民,一個個打電話通知他們。 **馬果果**對自己的這次出臺的規定非常滿意,當面對記者採訪的時候得意的說道,這是自己退休後堅持學習計算機,從計算機的檔案目錄中得到的靈感,人果然還是要「活到老學到老」啊! ![](https://img2020.cnblogs.com/blog/759200/202102/759200-20210202145930190-50909015.gif) --- 小故事講完了,下面用猿話翻譯一下: ZK 定義了每一個記錄必須有一個對應路徑,這個路徑就是對應小故事中的辦事處規定的分類,而整個記錄的結構的確和 Linux 中的檔案樹類似,有一個根節點 `/`,節點間有父子關係,路徑用 `/` 分割,比如: ``` /雞太美/更新視訊/跳舞/20201101 ``` 而故事中的標籤,其實就是客戶端中指定的 chroot,實際上是由客戶端維護的,服務端並不知道。 ### 1.2 程式碼實戰 特別說明接下來的實戰是用官方的 Java 客戶端作為演示的,新建一個空白的 Maven 專案,然後引入 ZK 的依賴: ```xml ``` 要操作 ZK 首先得先建立一個客戶端物件,我們以**雞太美**為例 ```java ZooKeeper client = new ZooKeeper("127.0.0.1:2181/雞太美", 3000, null); ``` `ZooKeeper`第一個字串就是連線的服務端地址,`/` 後面就是 `chroot`, 就是小故事裡的標籤,之後該客戶端所有的操作都會以`/雞太美`作為頂層路徑去處理。 最後當客戶端退出的時候,記得要關閉客戶端噢 ```java client.close(); ``` #### 1.2.1 建立路徑 這裡需要提醒的是,官方的客戶端是沒有遞迴建立的功能的,所以在建立多級路徑的時候,客戶端需要自己確保路徑中的父級節點是存在的! 下面的方法,直接執行是會報錯的,所以需要逐級建立 `20201101` 的父路徑,最終才能成功,這裡主要是演示結構,而之後的 `ZooDefs.Ids.OPEN_ACL_UNSAFE` 是一種 ACL 的許可權,意思就是不會進行許可權校驗,關於許可權,之後會有篇幅介紹,這裡直接跳過。 ```java client.create("/更新視訊/跳舞/20201101", "這是Data,既可以記錄一些業務資料也可以隨便寫".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); ``` 最後的 `CreateMode.PERSISTENT` 代表當前節點是一個持久型別的節點,`3.6.2` 中一共有 7 種類型,下面列出並且給出簡單解釋: ```java PERSISTENT // 持久節點,一旦建立成功不會被刪除,除非客戶端主動發起刪除請求 PERSISTENT_SEQUENTIAL // 持久順序節點,會在使用者路徑後面拼接一個不會重複的字增數字字尾,其他同上 EPHEMERAL // 臨時節點,當建立該節點的客戶端連結斷開後自動被刪除 EPHEMERAL_SEQUENTIAL // 臨時順序節點,基本同上,也是增加一個數字字尾 CONTAINER // 容器節點,一旦子節點被刪除完就會被服務端刪除 PERSISTENT_WITH_TTL // 帶過期時間的持久節點,帶有超時時間的節點,如果超時時間內沒有子節點被建立,就會被刪除 PERSISTENT_SEQUENTIAL_WITH_TTL // 帶過期時間的持久順序節點,基本同上,多了一個數字字尾 ``` 大家可能比較熟悉前四種,對後三種不太熟悉,特別是最後兩種帶 `TTL` 的型別,這兩種型別在 ZK 預設配置下還是不支援的,需要在 `zoo.cfg` 配置中新增 `extendedTypesEnabled=true` 啟用擴充套件功能,否則的話就會收到 `Unimplemented for` 的錯誤。 示例中路徑建立完就會是這樣: ``` 雞太美 |--更新視訊 |--跳舞 |--20201101 ``` #### 1.2.2 刪除路徑 官方的客戶端也不支援遞迴刪除,需要確保刪除的節點是葉子節點,否則就會收到錯誤,我們這裡把 20201101 給刪除: ```java client.delete("/更新視訊/跳舞/20201101", -1); ``` -1 是一個 version 欄位,相當於 ZK 提供的樂觀鎖機制,如果是 -1 的話就是無視節點的版本資訊。 刪除完就是這樣: ``` 雞太美 |--更新視訊 |--跳舞 ``` #### 1.2.3 設定資料 每一個節點都可以擁有自己的資料,既可以通過建立的時候指定,也可以在之後通過設定的方式指定。 ```java client.setData("/更新視訊/跳舞", "這是Data,可以寫一些關於業務的引數".getBytes(), -1); ``` -1 的含義和刪除路徑中是一樣的,也是無視版本資訊。 #### 1.2.4 判斷路徑是否存在 由於建立和刪除都不支援遞迴,所以需要對目標路徑進行判斷是否存在來決定是否進行下一步 ```java Stat stat = client.exists("/更新視訊", false); System.out.println(stat != null ? "存在" : "不存在"); // 存在 ``` false 意思是不進行訂閱,關於訂閱之後會一起說。 #### 1.2.5 獲取資料 能設定資料,必然也能獲取資料,所以 ZK 可以偶爾客串一下資料儲存的角色 ```java byte[] data = client.getData("/更新視訊/跳舞", false, null); System.out.println(new String(data)); // 這是Data,可以寫一些關於業務的引數 ``` #### 1.2.6 獲取子節點列表 前面說了 ZK 是一個樹形的結構,有父子節點概念,所以可以查詢某一個節點下面的所有子節點 ```java List