- ZooKeeper 教程
- ZooKeeper – 首頁
- ZooKeeper – 概述
- ZooKeeper - 基礎知識
- ZooKeeper – 工作流程
- ZooKeeper – Leader 選舉
- ZooKeeper – 安裝
- ZooKeeper – CLI
- ZooKeeper – API
- ZooKeeper – 應用
- ZooKeeper 有用資源
- ZooKeeper – 快速指南
- ZooKeeper – 有用資源
- ZooKeeper – 討論
ZooKeeper 快速指南
ZooKeeper - 概述
ZooKeeper 是一種分散式協調服務,用於管理大量主機。在分散式環境中協調和管理服務是一個複雜的過程。ZooKeeper 透過其簡單的架構和 API 解決了這個問題。ZooKeeper 允許開發人員專注於核心應用程式邏輯,而無需擔心應用程式的分散式特性。
ZooKeeper 框架最初是在“雅虎!”構建的,用於以簡單而可靠的方式訪問其應用程式。後來,Apache ZooKeeper 成為 Hadoop、HBase 和其他分散式框架使用的標準化服務。例如,Apache HBase 使用 ZooKeeper 來跟蹤分散式資料的狀態。
在繼續之前,瞭解一些關於分散式應用程式的資訊非常重要。因此,讓我們從分散式應用程式的快速概述開始討論。
分散式應用程式
分散式應用程式可以在網路中的多個系統上同時執行,透過相互協調以快速有效的方式完成特定任務。通常,複雜且耗時的任務(非分散式應用程式(在單個系統中執行)可能需要數小時才能完成)可以透過分散式應用程式在幾分鐘內完成,因為它利用了所有參與系統的計算能力。
透過將分散式應用程式配置為在更多系統上執行,可以進一步減少完成任務的時間。執行分散式應用程式的一組系統稱為**叢集**,叢集中執行的每臺機器稱為**節點**。
分散式應用程式有兩個部分:**伺服器**和**客戶端**應用程式。伺服器應用程式實際上是分散式的,並且具有公共介面,以便客戶端可以連線到叢集中的任何伺服器並獲得相同的結果。客戶端應用程式是與分散式應用程式互動的工具。
分散式應用程式的優勢
**可靠性** - 單個或少數幾個系統的故障不會導致整個系統故障。
**可擴充套件性** - 可以根據需要透過新增更多機器來提高效能,只需對應用程式進行少量配置更改,並且無需停機。
**透明性** - 隱藏系統的複雜性,並顯示為單個實體/應用程式。
分散式應用程式的挑戰
**競爭條件** - 兩臺或多臺機器嘗試執行特定任務,而該任務實際上在任何給定時間只能由一臺機器執行。例如,共享資源在任何給定時間只能由一臺機器修改。
**死鎖** - 兩臺或多臺操作無限期地等待彼此完成。
**不一致性** - 資料的部分故障。
Apache ZooKeeper 的用途是什麼?
Apache ZooKeeper 是一種由叢集(節點組)使用的服務,用於在它們之間進行協調並使用強大的同步技術維護共享資料。ZooKeeper 本身就是一個分散式應用程式,提供編寫分散式應用程式的服務。
ZooKeeper 提供的常見服務如下:
**命名服務** - 透過名稱識別叢集中的節點。它類似於 DNS,但用於節點。
**配置管理** - 為加入的節點提供系統最新和最新的配置資訊。
**叢集管理** - 節點加入/離開叢集以及即時節點狀態。
**Leader 選舉** - 選舉一個節點作為協調目的的領導者。
**鎖定和同步服務** - 在修改資料時鎖定資料。此機制有助於在連線其他分散式應用程式(如 Apache HBase)時實現自動故障恢復。
**高可靠性資料登錄檔** - 即使一個或幾個節點出現故障,也能保證資料的可用性。
分散式應用程式提供了許多好處,但也帶來了一些複雜且難以解決的挑戰。ZooKeeper 框架提供了一種完整的機制來克服所有這些挑戰。競爭條件和死鎖使用**故障安全同步方法**處理。另一個主要缺點是不一致的資料,ZooKeeper 透過**原子性**解決了這個問題。
ZooKeeper 的優勢
以下是使用 ZooKeeper 的優勢:
簡單的分散式協調過程
**同步** - 伺服器程序之間的互斥和協作。此過程有助於 Apache HBase 進行配置管理。
有序訊息
**序列化** - 根據特定規則編碼資料。確保您的應用程式一致執行。此方法可用於 MapReduce 協調佇列以執行正在執行的執行緒。
可靠性
**原子性** - 資料傳輸要麼完全成功,要麼完全失敗,但沒有部分事務。
ZooKeeper - 基礎知識
在深入研究 ZooKeeper 的工作原理之前,讓我們先了解一下 ZooKeeper 的基本概念。我們將在本章中討論以下主題:
- 架構
- 分層名稱空間
- 會話
- 監視器
ZooKeeper 的架構
請檢視下圖。它描述了 ZooKeeper 的“客戶端-伺服器架構”。
ZooKeeper 架構中每個元件都在下表中進行了說明。
| 部分 | 描述 |
|---|---|
| 客戶端 | 客戶端(我們分散式應用程式叢集中的節點之一)從伺服器訪問資訊。在特定時間間隔內,每個客戶端都會向伺服器傳送一條訊息,以告知伺服器客戶端處於活動狀態。 同樣,伺服器在客戶端連線時會發送確認。如果從連線的伺服器沒有響應,客戶端會自動將訊息重定向到另一個伺服器。 |
| 伺服器 | 伺服器(我們 ZooKeeper 叢集中的節點之一)為客戶端提供所有服務。向客戶端傳送確認以告知伺服器處於活動狀態。 |
| 叢集 | ZooKeeper 伺服器組。形成叢集所需的最小節點數為 3。 |
| 領導者 | 伺服器節點,如果任何連線的節點發生故障,則執行自動恢復。領導者在服務啟動時選舉產生。 |
| 跟隨者 | 遵循領導者指令的伺服器節點。 |
分層名稱空間
下圖描述了用於記憶體表示的 ZooKeeper 檔案系統的樹結構。ZooKeeper 節點稱為**znode**。每個 znode 都由一個名稱標識,並由路徑序列(/)分隔。
在圖中,首先有一個根**znode**,由“/”分隔。在根目錄下,有兩個邏輯名稱空間**config**和**workers**。
**config**名稱空間用於集中式配置管理,而**workers**名稱空間用於命名。
在**config**名稱空間下,每個 znode 可以儲存最多 1MB 的資料。這類似於 UNIX 檔案系統,只是父 znode 也可以儲存資料。此結構的主要目的是儲存同步資料並描述 znode 的元資料。此結構稱為**ZooKeeper 資料模型**。
ZooKeeper 資料模型中的每個 znode 都維護一個**stat**結構。stat 簡單地提供 znode 的**元資料**。它包括*版本號、訪問控制列表 (ACL)、時間戳和資料長度*。
**版本號** - 每個 znode 都有一個版本號,這意味著每次與 znode 關聯的資料發生更改時,其相應的版本號也會增加。當多個 Zookeeper 客戶端嘗試對同一個 znode 執行操作時,版本號的使用非常重要。
**訪問控制列表 (ACL)** - ACL 基本上是訪問 znode 的身份驗證機制。它控制所有 znode 的讀寫操作。
**時間戳** - 時間戳表示從 znode 建立和修改開始經過的時間。通常以毫秒錶示。ZooKeeper 透過“事務 ID”(zxid)識別對 znode 的每次更改。**Zxid** 是唯一的,併為每個事務維護時間,以便您可以輕鬆識別從一個請求到另一個請求經過的時間。
**資料長度** - 儲存在 znode 中的資料總量就是資料長度。您可以儲存最多 1MB 的資料。
Znode 的型別
Znode 分為永續性、順序和臨時性。
**永續性 znode** - 即使建立該特定 znode 的客戶端斷開連線,永續性 znode 也仍然存在。預設情況下,所有 znode 都是永續性的,除非另有指定。
**臨時 znode** - 臨時 znode 在客戶端處於活動狀態時處於活動狀態。當客戶端與 ZooKeeper 叢集斷開連線時,臨時 znode 會自動刪除。因此,僅臨時 znode 不允許有子節點。如果臨時 znode 被刪除,則下一個合適的節點將填充其位置。臨時 znode 在 Leader 選舉中起著重要作用。
**順序 znode** - 順序 znode 可以是永續性的或臨時性的。當建立一個新的 znode 作為順序 znode 時,ZooKeeper 會透過在原始名稱後附加一個 10 位序列號來設定 znode 的路徑。例如,如果一個路徑為** /myapp**的 znode 被建立為順序 znode,ZooKeeper 將路徑更改為** /myapp0000000001**並將下一個序列號設定為 0000000002。如果同時建立兩個順序 znode,則 ZooKeeper 永遠不會對每個 znode 使用相同的數字。順序 znode 在鎖定和同步中起著重要作用。
會話
會話對於 ZooKeeper 的操作非常重要。會話中的請求按 FIFO 順序執行。客戶端連線到伺服器後,將建立會話併為客戶端分配一個**會話 ID**。
客戶端以特定時間間隔傳送**心跳**以保持會話有效。如果 ZooKeeper 叢集在服務啟動時指定的時間段(會話超時)內未收到客戶端的心跳,則它會認為客戶端已死。
會話超時通常以毫秒錶示。無論出於何種原因,會話結束時,在該會話期間建立的臨時 znode 也會被刪除。
監視器
監視器是客戶端獲取 ZooKeeper 叢集更改通知的簡單機制。客戶端在讀取特定 znode 時可以設定監視器。監視器會為任何 znode(客戶端在其中註冊)更改向註冊的客戶端傳送通知。
Znode 的更改是指與 znode 關聯的資料的修改或 znode 子節點的更改。Watch 只觸發一次。如果客戶端想要再次收到通知,則必須透過另一個讀取操作來實現。當連線會話過期時,客戶端將與伺服器斷開連線,並且關聯的 watch 也會被移除。
Zookeeper - 工作流程
ZooKeeper 叢集啟動後,將等待客戶端連線。客戶端將連線到 ZooKeeper 叢集中的一個節點。它可能是一個領導者節點或一個跟隨者節點。客戶端連線後,節點會為該特定客戶端分配一個會話 ID 並向客戶端傳送確認訊息。如果客戶端沒有收到確認訊息,它會簡單地嘗試連線 ZooKeeper 叢集中的另一個節點。連線到節點後,客戶端將以固定的時間間隔向節點發送心跳,以確保連線不會丟失。
如果客戶端想要讀取特定的 znode,它會向節點發送一個包含 znode 路徑的讀取請求,節點會從自己的資料庫中獲取請求的 znode 並將其返回。因此,ZooKeeper 叢集中的讀取操作非常快。
如果客戶端想要將資料儲存到 ZooKeeper 叢集中,它會將 znode 路徑和資料傳送到伺服器。連線的伺服器會將請求轉發到領導者節點,然後領導者節點會向所有跟隨者節點重新發布寫入請求。只有當大多數節點成功響應時,寫入請求才會成功,並且會向客戶端傳送成功返回程式碼。否則,寫入請求將失敗。節點的嚴格多數被稱為Quorum(仲裁)。
ZooKeeper 叢集中的節點
讓我們分析一下在 ZooKeeper 叢集中使用不同數量的節點的影響。
如果我們只有一個節點,那麼當該節點發生故障時,ZooKeeper 叢集就會失效。這會導致“單點故障”,在生產環境中不建議使用。
如果我們有兩個節點,並且一個節點發生故障,我們也沒有多數,因為兩個節點中只有一個節點不足以構成多數。
如果我們有三個節點,並且一個節點發生故障,我們仍然有多數,因此這是最低要求。在實際生產環境中,ZooKeeper 叢集必須至少有三個節點。
如果我們有四個節點,並且兩個節點發生故障,它也會失效,這與只有三個節點的情況類似。額外的節點沒有任何作用,因此最好以奇數新增節點,例如 3、5、7。
我們知道,在 ZooKeeper 叢集中,寫入過程比讀取過程開銷更大,因為所有節點都需要將其資料庫中的資料寫入相同的資料。因此,為了保持環境的平衡,最好使用較少的節點(3、5 或 7),而不是使用大量的節點。
下圖描述了 ZooKeeper 的工作流程,後續表格解釋了其不同的元件。
| 元件 | 描述 |
|---|---|
| 寫入 | 寫入過程由領導者節點處理。領導者節點將寫入請求轉發到所有 znode 並等待來自 znode 的響應。如果一半的 znode 回覆,則寫入過程完成。 |
| 讀取 | 讀取操作由特定的連線 znode 內部執行,因此無需與叢集互動。 |
| 複製資料庫 | 它用於在 Zookeeper 中儲存資料。每個 znode 都有自己的資料庫,並且在一致性的幫助下,每個 znode 在任何時間都具有相同的資料。 |
| 領導者 | 領導者是負責處理寫入請求的 Znode。 |
| 跟隨者 | 跟隨者從客戶端接收寫入請求並將其轉發到領導者 znode。 |
| 請求處理器 | 僅存在於領導者節點中。它管理來自跟隨者節點的寫入請求。 |
| 原子廣播 | 負責將更改從領導者節點廣播到跟隨者節點。 |
Zookeeper - 領導者選舉
讓我們分析一下如何在 ZooKeeper 叢集中選舉領導者節點。假設叢集中有N個節點。領導者選舉過程如下:
所有節點都建立一個具有相同路徑的順序、短暫的 znode,/app/leader_election/guid_。
ZooKeeper 叢集會將 10 位序列號附加到路徑中,建立的 znode 將是/app/leader_election/guid_0000000001、/app/leader_election/guid_0000000002等。
對於給定的例項,在 znode 中建立最小數字的節點成為領導者,所有其他節點都是跟隨者。
每個跟隨者節點都監視具有下一個最小數字的 znode。例如,建立 znode /app/leader_election/guid_0000000008 的節點將監視 znode /app/leader_election/guid_0000000007,而建立 znode /app/leader_election/guid_0000000007 的節點將監視 znode /app/leader_election/guid_0000000006。
如果領導者節點宕機,則其對應的 znode /app/leader_electionN 將被刪除。
排在後面的跟隨者節點將透過監視器收到關於領導者移除的通知。
排在後面的跟隨者節點將檢查是否還有其他 znode 具有最小數字。如果沒有,則它將承擔領導者的角色。否則,它會找到建立具有最小數字的 znode 的節點作為領導者。
類似地,所有其他跟隨者節點都會選舉建立具有最小數字的 znode 的節點作為領導者。
從頭開始進行領導者選舉是一個複雜的過程。但是 ZooKeeper 服務使它變得非常簡單。在下一章中,我們將繼續介紹 ZooKeeper 的安裝,以便用於開發目的。
Zookeeper - 安裝
在安裝 ZooKeeper 之前,請確保您的系統正在執行以下任何作業系統:
任何 Linux 作業系統 - 支援開發和部署。它適合於演示應用程式。
Windows 作業系統 - 只支援開發。
Mac OS - 只支援開發。
ZooKeeper 伺服器是用 Java 建立的,它執行在 JVM 上。您需要使用 JDK 6 或更高版本。
現在,請按照以下步驟在您的機器上安裝 ZooKeeper 框架。
步驟 1:驗證 Java 安裝
我們相信您已經在系統上安裝了 Java 環境。只需使用以下命令驗證它即可。
$ java -version
如果您的機器上安裝了 Java,則可以看到已安裝 Java 的版本。否則,請按照以下簡單步驟安裝最新版本的 Java。
步驟 1.1:下載 JDK
訪問以下連結下載最新版本的 JDK,並下載最新版本。Java
最新版本(編寫本教程時)是 JDK 8u 60,檔名為“jdk-8u60-linuxx64.tar.gz”。請將檔案下載到您的機器上。
步驟 1.2:解壓縮檔案
通常,檔案會被下載到downloads資料夾中。驗證它並使用以下命令解壓縮 tar 設定。
$ cd /go/to/download/path $ tar -zxf jdk-8u60-linux-x64.gz
步驟 1.3:移動到 opt 目錄
為了使所有使用者都能使用 Java,請將解壓縮的 Java 內容移動到“/usr/local/java”資料夾。
$ su password: (type password of root user) $ mkdir /opt/jdk $ mv jdk-1.8.0_60 /opt/jdk/
步驟 1.4:設定路徑
要設定路徑和 JAVA_HOME 變數,請將以下命令新增到 ~/.bashrc 檔案中。
export JAVA_HOME = /usr/jdk/jdk-1.8.0_60 export PATH=$PATH:$JAVA_HOME/bin
現在,將所有更改應用到當前正在執行的系統中。
$ source ~/.bashrc
步驟 1.5:Java 備選方案
使用以下命令更改 Java 備選方案。
update-alternatives --install /usr/bin/java java /opt/jdk/jdk1.8.0_60/bin/java 100
步驟 1.6
使用步驟 1 中說明的驗證命令(java -version)驗證 Java 安裝。
步驟 2:ZooKeeper 框架安裝
步驟 2.1:下載 ZooKeeper
要在您的機器上安裝 ZooKeeper 框架,請訪問以下連結並下載最新版本的 ZooKeeper。http://zookeeper.apache.org/releases.html
截至目前,ZooKeeper 的最新版本是 3.4.6 (ZooKeeper-3.4.6.tar.gz)。
步驟 2.2:解壓縮 tar 檔案
使用以下命令解壓縮 tar 檔案:
$ cd opt/ $ tar -zxf zookeeper-3.4.6.tar.gz $ cd zookeeper-3.4.6 $ mkdir data
步驟 2.3:建立配置檔案
使用命令vi conf/zoo.cfg開啟名為conf/zoo.cfg的配置檔案,並將所有以下引數設定為起點。
$ vi conf/zoo.cfg tickTime = 2000 dataDir = /path/to/zookeeper/data clientPort = 2181 initLimit = 5 syncLimit = 2
配置檔案儲存成功後,再次返回終端。現在可以啟動 Zookeeper 伺服器了。
步驟 2.4:啟動 ZooKeeper 伺服器
執行以下命令:
$ bin/zkServer.sh start
執行此命令後,您將收到如下響應:
$ JMX enabled by default $ Using config: /Users/../zookeeper-3.4.6/bin/../conf/zoo.cfg $ Starting zookeeper ... STARTED
步驟 2.5:啟動 CLI
鍵入以下命令:
$ bin/zkCli.sh
鍵入上述命令後,您將連線到 ZooKeeper 伺服器,並且應該收到以下響應。
Connecting to localhost:2181 ................ ................ ................ Welcome to ZooKeeper! ................ ................ WATCHER:: WatchedEvent state:SyncConnected type: None path:null [zk: localhost:2181(CONNECTED) 0]
停止 ZooKeeper 伺服器
連線伺服器並執行所有操作後,可以使用以下命令停止 Zookeeper 伺服器。
$ bin/zkServer.sh stop
Zookeeper - CLI
ZooKeeper 命令列介面 (CLI) 用於與 ZooKeeper 叢集互動以進行開發。它有助於除錯和處理不同的選項。
要執行 ZooKeeper CLI 操作,首先開啟 ZooKeeper 伺服器(“bin/zkServer.sh start”),然後開啟 ZooKeeper 客戶端(“bin/zkCli.sh”)。客戶端啟動後,您可以執行以下操作:
- 建立 znode
- 獲取資料
- 監視 znode 的更改
- 設定資料
- 建立 znode 的子節點
- 列出 znode 的子節點
- 檢查狀態
- 移除/刪除 znode
現在讓我們逐一檢視以上命令並舉例說明。
建立 Znode
使用給定的路徑建立一個 znode。flag引數指定建立的 znode 是否是短暫的、持久的或順序的。預設情況下,所有 znode 都是持久的。
短暫的 znode(flag:e)會在會話過期或客戶端斷開連線時自動刪除。
順序的 znode保證 znode 路徑是唯一的。
ZooKeeper 叢集會在 znode 路徑後面新增序列號,並使用 10 位數字進行填充。例如,znode 路徑/myapp 會轉換為 /myapp0000000001,下一個序列號將是/myapp0000000002。如果未指定任何標誌,則 znode 被視為永續性的。
語法
create /path /data
示例
create /FirstZnode “Myfirstzookeeper-app”
輸出
[zk: localhost:2181(CONNECTED) 0] create /FirstZnode “Myfirstzookeeper-app” Created /FirstZnode
要建立順序 znode,請新增-s 標誌,如下所示。
語法
create -s /path /data
示例
create -s /FirstZnode second-data
輸出
[zk: localhost:2181(CONNECTED) 2] create -s /FirstZnode “second-data” Created /FirstZnode0000000023
要建立臨時 Znode,請新增-e 標誌,如下所示。
語法
create -e /path /data
示例
create -e /SecondZnode “Ephemeral-data”
輸出
[zk: localhost:2181(CONNECTED) 2] create -e /SecondZnode “Ephemeral-data” Created /SecondZnode
請記住,當客戶端連線丟失時,臨時 znode 將被刪除。您可以嘗試退出 ZooKeeper CLI,然後重新開啟 CLI。
獲取資料
它返回 znode 的關聯資料和指定 znode 的元資料。您將獲得有關資料上次修改時間、修改位置以及資料資訊等資訊。此 CLI 也用於分配監視器以顯示有關資料的通知。
語法
get /path
示例
get /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0
要訪問順序 znode,您必須輸入 znode 的完整路徑。
示例
get /FirstZnode0000000023
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode0000000023 “Second-data” cZxid = 0x80 ctime = Tue Sep 29 16:25:47 IST 2015 mZxid = 0x80 mtime = Tue Sep 29 16:25:47 IST 2015 pZxid = 0x80 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 13 numChildren = 0
監視
監視在指定 znode 或 znode 的子節點資料更改時顯示通知。您只能在get命令中設定監視。
語法
get /path [watch] 1
示例
get /FirstZnode 1
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode 1 “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0
輸出類似於普通的get命令,但它將在後臺等待 znode 更改。<從這裡開始>
設定資料
設定指定 znode 的資料。完成此設定操作後,您可以使用get CLI 命令檢查資料。
語法
set /path /data
示例
set /SecondZnode Data-updated
輸出
[zk: localhost:2181(CONNECTED) 1] get /SecondZnode “Data-updated” cZxid = 0x82 ctime = Tue Sep 29 16:29:50 IST 2015 mZxid = 0x83 mtime = Tue Sep 29 16:29:50 IST 2015 pZxid = 0x82 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x15018b47db00000 dataLength = 14 numChildren = 0
如果您在get命令中分配了監視選項(如上一個命令),則輸出將類似於以下所示:
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Mysecondzookeeper-app” WATCHER: : WatchedEvent state:SyncConnected type:NodeDataChanged path:/FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x84 mtime = Tue Sep 29 17:14:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0
建立子節點/子 znode
建立子節點類似於建立新的 znode。唯一的區別是子 znode 的路徑也將包含父路徑。
語法
create /parent/path/subnode/path /data
示例
create /FirstZnode/Child1 firstchildren
輸出
[zk: localhost:2181(CONNECTED) 16] create /FirstZnode/Child1 “firstchildren” created /FirstZnode/Child1 [zk: localhost:2181(CONNECTED) 17] create /FirstZnode/Child2 “secondchildren” created /FirstZnode/Child2
列出子節點
此命令用於列出和顯示 znode 的子節點。
語法
ls /path
示例
ls /MyFirstZnode
輸出
[zk: localhost:2181(CONNECTED) 2] ls /MyFirstZnode [mysecondsubnode, myfirstsubnode]
檢查狀態
狀態描述指定 znode 的元資料。它包含時間戳、版本號、ACL、資料長度和子 znode 等詳細資訊。
語法
stat /path
示例
stat /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 1] stat /FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 17:14:24 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0
刪除 Znode
刪除指定的 znode 及其所有子節點(遞迴)。只有在存在此類 znode 時才會發生這種情況。
語法
rmr /path
示例
rmr /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 10] rmr /FirstZnode [zk: localhost:2181(CONNECTED) 11] get /FirstZnode Node does not exist: /FirstZnode
delete /path 命令類似於remove命令,不同之處在於它僅適用於沒有子節點的 znode。
Zookeeper - API
ZooKeeper 具有針對 Java 和 C 的官方 API 繫結。ZooKeeper 社群為大多數語言(.NET、python 等)提供了非官方 API。使用 ZooKeeper API,應用程式可以連線、互動、操作資料、協調,最後斷開與 ZooKeeper 叢集的連線。
ZooKeeper API 具有豐富的功能集,可以以簡單安全的方式獲取 ZooKeeper 叢集的所有功能。ZooKeeper API 提供同步和非同步方法。
ZooKeeper 叢集和 ZooKeeper API 在各個方面完全互補,這對開發人員非常有利。在本章中,我們將討論 Java 繫結。
ZooKeeper API 基礎
與 ZooKeeper 叢集互動的應用程式稱為ZooKeeper 客戶端或簡稱為客戶端。
Znode 是 ZooKeeper 叢集的核心元件,ZooKeeper API 提供了一小組方法來操作 znode 與 ZooKeeper 叢集的所有詳細資訊。
客戶端應遵循以下步驟,以便與 ZooKeeper 叢集進行清晰乾淨的互動。
連線到 ZooKeeper 叢集。ZooKeeper 叢集為客戶端分配一個會話 ID。
定期向伺服器傳送心跳。否則,ZooKeeper 叢集將使會話 ID 過期,客戶端需要重新連線。
只要會話 ID 有效,就可以獲取/設定 znode。
完成所有任務後,斷開與 ZooKeeper 叢集的連線。如果客戶端長時間處於非活動狀態,則 ZooKeeper 叢集將自動斷開客戶端的連線。
Java 繫結
讓我們在本章中瞭解 ZooKeeper API 中最重要的一組 API。ZooKeeper API 的核心部分是ZooKeeper 類。它提供在建構函式中連線 ZooKeeper 叢集的選項,並具有以下方法:
connect - 連線到 ZooKeeper 叢集
create - 建立 znode
exists - 檢查 znode 是否存在及其資訊
getData - 從特定 znode 獲取資料
setData - 在特定 znode 中設定資料
getChildren - 獲取特定 znode 中可用的所有子節點
delete - 獲取特定 znode 及其所有子節點
close - 關閉連線
連線到 ZooKeeper 叢集
ZooKeeper 類透過其建構函式提供連線功能。建構函式的簽名如下:
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher)
其中,
connectionString - ZooKeeper 叢集主機。
sessionTimeout - 會話超時(毫秒)。
watcher - 實現“Watcher”介面的物件。ZooKeeper 叢集透過 watcher 物件返回連線狀態。
讓我們建立一個新的輔助類ZooKeeperConnection並新增一個方法connect。connect方法建立一個 ZooKeeper 物件,連線到 ZooKeeper 叢集,然後返回該物件。
這裡CountDownLatch用於停止(等待)主程序,直到客戶端與 ZooKeeper 叢集連線。
ZooKeeper 叢集透過Watcher 回撥回覆連線狀態。一旦客戶端與 ZooKeeper 叢集連線,Watcher 回撥將被呼叫,並且 Watcher 回撥呼叫CountDownLatch的countDown方法來釋放鎖,主程序中的await。
以下是連線 ZooKeeper 叢集的完整程式碼。
編碼:ZooKeeperConnection.java
// import java classes
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
// import zookeeper classes
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.data.Stat;
public class ZooKeeperConnection {
// declare zookeeper instance to access ZooKeeper ensemble
private ZooKeeper zoo;
final CountDownLatch connectedSignal = new CountDownLatch(1);
// Method to connect zookeeper ensemble.
public ZooKeeper connect(String host) throws IOException,InterruptedException {
zoo = new ZooKeeper(host,5000,new Watcher() {
public void process(WatchedEvent we) {
if (we.getState() == KeeperState.SyncConnected) {
connectedSignal.countDown();
}
}
});
connectedSignal.await();
return zoo;
}
// Method to disconnect from zookeeper server
public void close() throws InterruptedException {
zoo.close();
}
}
儲存上述程式碼,它將在下一節中用於連線 ZooKeeper 叢集。
建立 Znode
ZooKeeper 類提供create 方法在 ZooKeeper 叢集中建立新的 znode。create方法的簽名如下:
create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
其中,
path - Znode 路徑。例如,/myapp1、/myapp2、/myapp1/mydata1、myapp2/mydata1/myanothersubdata
data - 要儲存在指定 znode 路徑中的資料
acl - 要建立的節點的訪問控制列表。ZooKeeper API 提供了一個靜態介面ZooDefs.Ids來獲取一些基本的 acl 列表。例如,ZooDefs.Ids.OPEN_ACL_UNSAFE 返回開放 znode 的 acl 列表。
createMode - 節點型別,可以是臨時、順序或兩者兼而有之。這是一個列舉。
讓我們建立一個新的 Java 應用程式來檢查 ZooKeeper API 的create功能。建立一個檔案ZKCreate.java。在 main 方法中,建立一個型別為ZooKeeperConnection的物件並呼叫connect方法連線到 ZooKeeper 叢集。
connect 方法將返回 ZooKeeper 物件zk。現在,使用自定義path和data呼叫zk物件的create方法。
建立 znode 的完整程式程式碼如下:
編碼:ZKCreate.java
import java.io.IOException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
public class ZKCreate {
// create static instance for zookeeper class.
private static ZooKeeper zk;
// create static instance for ZooKeeperConnection class.
private static ZooKeeperConnection conn;
// Method to create znode in zookeeper ensemble
public static void create(String path, byte[] data) throws
KeeperException,InterruptedException {
zk.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
public static void main(String[] args) {
// znode path
String path = "/MyFirstZnode"; // Assign path to znode
// data in byte array
byte[] data = "My first zookeeper app”.getBytes(); // Declare data
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
create(path, data); // Create the data to the specified path
conn.close();
} catch (Exception e) {
System.out.println(e.getMessage()); //Catch error message
}
}
}
應用程式編譯並執行後,將在 ZooKeeper 叢集中建立具有指定資料的 znode。您可以使用 ZooKeeper CLI zkCli.sh進行檢查。
cd /path/to/zookeeper bin/zkCli.sh >>> get /MyFirstZnode
Exists – 檢查 Znode 的存在性
ZooKeeper 類提供exists 方法來檢查 znode 的存在性。如果指定的 znode 存在,則返回 znode 的元資料。exists方法的簽名如下:
exists(String path, boolean watcher)
其中,
path - Znode 路徑
watcher - 布林值,用於指定是否監視指定的 znode
讓我們建立一個新的 Java 應用程式來檢查 ZooKeeper API 的“exists”功能。建立一個檔案“ZKExists.java”。在 main 方法中,使用“ZooKeeperConnection”物件建立 ZooKeeper 物件“zk”。然後,使用自定義“path”呼叫“zk”物件的“exists”方法。完整的列表如下:
編碼:ZKExists.java
import java.io.IOException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKExists {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path, true);
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; // Assign znode to the specified path
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path); // Stat checks the path of the znode
if(stat != null) {
System.out.println("Node exists and the node version is " +
stat.getVersion());
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage()); // Catches error messages
}
}
}
應用程式編譯並執行後,您將獲得以下輸出。
Node exists and the node version is 1.
getData 方法
ZooKeeper 類提供getData方法來獲取附加在指定 znode 中的資料及其狀態。getData方法的簽名如下:
getData(String path, Watcher watcher, Stat stat)
其中,
path - Znode 路徑。
watcher - 型別為Watcher的回撥函式。當指定 znode 的資料發生變化時,ZooKeeper 叢集將透過 Watcher 回撥進行通知。這是一次性通知。
stat - 返回 znode 的元資料。
讓我們建立一個新的 Java 應用程式來了解 ZooKeeper API 的getData功能。建立一個檔案ZKGetData.java。在 main 方法中,使用ZooKeeperConnection物件建立一個 ZooKeeper 物件zk。然後,使用自定義路徑呼叫zk物件的getData方法。
以下是從指定節點獲取資料的完整程式程式碼:
編碼:ZKGetData.java
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKGetData {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path,true);
}
public static void main(String[] args) throws InterruptedException, KeeperException {
String path = "/MyFirstZnode";
final CountDownLatch connectedSignal = new CountDownLatch(1);
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path);
if(stat != null) {
byte[] b = zk.getData(path, new Watcher() {
public void process(WatchedEvent we) {
if (we.getType() == Event.EventType.None) {
switch(we.getState()) {
case Expired:
connectedSignal.countDown();
break;
}
} else {
String path = "/MyFirstZnode";
try {
byte[] bn = zk.getData(path,
false, null);
String data = new String(bn,
"UTF-8");
System.out.println(data);
connectedSignal.countDown();
} catch(Exception ex) {
System.out.println(ex.getMessage());
}
}
}
}, null);
String data = new String(b, "UTF-8");
System.out.println(data);
connectedSignal.await();
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
應用程式編譯並執行後,您將獲得以下輸出
My first zookeeper app
並且應用程式將等待 ZooKeeper 叢集的進一步通知。使用 ZooKeeper CLI zkCli.sh更改指定 znode 的資料。
cd /path/to/zookeeper bin/zkCli.sh >>> set /MyFirstZnode Hello
現在,應用程式將列印以下輸出並退出。
Hello
setData 方法
ZooKeeper 類提供setData方法來修改附加在指定 znode 中的資料。setData方法的簽名如下:
setData(String path, byte[] data, int version)
其中,
path - Znode 路徑
data - 要儲存在指定 znode 路徑中的資料。
version - znode 的當前版本。每當資料發生更改時,ZooKeeper 都會更新 znode 的版本號。
現在讓我們建立一個新的 Java 應用程式來了解 ZooKeeper API 的setData功能。建立一個檔案ZKSetData.java。在 main 方法中,使用ZooKeeperConnection物件建立一個 ZooKeeper 物件zk。然後,使用指定的路徑、新資料和節點版本呼叫zk物件的setData方法。
以下是修改附加在指定 znode 中的資料的完整程式程式碼。
程式碼:ZKSetData.java
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import java.io.IOException;
public class ZKSetData {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to update the data in a znode. Similar to getData but without watcher.
public static void update(String path, byte[] data) throws
KeeperException,InterruptedException {
zk.setData(path, data, zk.exists(path,true).getVersion());
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path= "/MyFirstZnode";
byte[] data = "Success".getBytes(); //Assign data which is to be updated.
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
update(path, data); // Update znode data to the specified path
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
應用程式編譯並執行後,指定 znode 的資料將被更改,可以使用 ZooKeeper CLI zkCli.sh進行檢查。
cd /path/to/zookeeper bin/zkCli.sh >>> get /MyFirstZnode
getChildrenMethod
ZooKeeper 類提供getChildren方法來獲取特定 znode 的所有子節點。getChildren方法的簽名如下:
getChildren(String path, Watcher watcher)
其中,
path - Znode 路徑。
watcher - 型別為“Watcher”的回撥函式。當指定的 znode 被刪除或 znode 下的子節點被建立/刪除時,ZooKeeper 叢集將發出通知。這是一次性通知。
編碼:ZKGetChildren.java
import java.io.IOException;
import java.util.*;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.data.Stat;
public class ZKGetChildren {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static Stat znode_exists(String path) throws
KeeperException,InterruptedException {
return zk.exists(path,true);
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; // Assign path to the znode
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
Stat stat = znode_exists(path); // Stat checks the path
if(stat!= null) {
//“getChildren” method- get all the children of znode.It has two
args, path and watch
List <String> children = zk.getChildren(path, false);
for(int i = 0; i < children.size(); i++)
System.out.println(children.get(i)); //Print children's
} else {
System.out.println("Node does not exists");
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
在執行程式之前,讓我們使用 ZooKeeper CLI zkCli.sh為/MyFirstZnode建立兩個子節點。
cd /path/to/zookeeper bin/zkCli.sh >>> create /MyFirstZnode/myfirstsubnode Hi >>> create /MyFirstZnode/mysecondsubmode Hi
現在,編譯並執行程式將輸出上面建立的 znode。
myfirstsubnode mysecondsubnode
刪除 Znode
ZooKeeper 類提供delete方法來刪除指定的 znode。delete方法的簽名如下:
delete(String path, int version)
其中,
path - Znode 路徑。
version - znode 的當前版本。
讓我們建立一個新的 Java 應用程式來了解 ZooKeeper API 的delete功能。建立一個檔案ZKDelete.java。在 main 方法中,使用ZooKeeperConnection物件建立一個 ZooKeeper 物件zk。然後,使用指定的path和節點版本呼叫zk物件的delete方法。
刪除 znode 的完整程式程式碼如下:
編碼:ZKDelete.java
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException;
public class ZKDelete {
private static ZooKeeper zk;
private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available.
public static void delete(String path) throws KeeperException,InterruptedException {
zk.delete(path,zk.exists(path,true).getVersion());
}
public static void main(String[] args) throws InterruptedException,KeeperException {
String path = "/MyFirstZnode"; //Assign path to the znode
try {
conn = new ZooKeeperConnection();
zk = conn.connect("localhost");
delete(path); //delete the node with the specified path
} catch(Exception e) {
System.out.println(e.getMessage()); // catches error messages
}
}
}
Zookeeper - 應用
Zookeeper 為分散式環境提供靈活的協調基礎架構。ZooKeeper 框架支援當今許多最佳的工業應用。我們將在本章中討論 ZooKeeper 的一些最著名的應用。
雅虎!
ZooKeeper 框架最初由“雅虎”開發。一個設計良好的分散式應用程式需要滿足諸如資料透明性、更好的效能、魯棒性、集中式配置和協調等需求。因此,他們設計了 ZooKeeper 框架來滿足這些需求。
Apache Hadoop
Apache Hadoop 是大資料行業發展背後的驅動力。Hadoop 依靠 ZooKeeper 進行配置管理和協調。讓我們透過一個場景來理解 ZooKeeper 在 Hadoop 中的作用。
假設一個**Hadoop 叢集**連線了**100 臺或更多商品伺服器**。因此,需要協調和命名服務。由於涉及大量節點的計算,每個節點都需要彼此同步,知道在哪裡訪問服務,以及如何配置它們。此時,Hadoop 叢集需要跨節點服務。ZooKeeper 提供了**跨節點同步**的功能,並確保 Hadoop 專案中的任務被序列化和同步。
多個 ZooKeeper 伺服器支援大型 Hadoop 叢集。每個客戶端機器都與其中一個 ZooKeeper 伺服器通訊,以檢索和更新其同步資訊。一些即時示例如下:
**人類基因組計劃** - 人類基因組計劃包含數TB的資料。Hadoop MapReduce 框架可用於分析資料集並發現人類發展方面的重要資訊。
**醫療保健** - 醫院可以儲存、檢索和分析大量的患者醫療記錄,這些記錄通常以TB為單位。
Apache HBase
Apache HBase 是一個開源的、分散式的、NoSQL 資料庫,用於對大型資料集進行即時讀/寫訪問,並且執行在 HDFS 之上。HBase 遵循**主從架構**,其中 HBase Master 控制所有從節點。從節點被稱為**區域伺服器**。
HBase 分散式應用程式的安裝依賴於正在執行的 ZooKeeper 叢集。Apache HBase 使用 ZooKeeper 透過**集中式配置管理**和**分散式互斥**機制來跟蹤主節點和區域伺服器之間分散式資料的狀態。以下是 HBase 的一些用例:
**電信** - 電信行業儲存數十億條移動通話記錄(大約 30TB/月),並且即時訪問這些通話記錄成為一項巨大的任務。HBase 可用於輕鬆高效地即時處理所有記錄。
**社交網路** - 與電信行業類似,Twitter、LinkedIn 和 Facebook 等網站透過使用者建立的帖子接收大量資料。HBase 可用於查詢最新趨勢和其他有趣的資訊。
Apache Solr
Apache Solr 是一個用 Java 編寫的快速開源搜尋平臺。它是一個閃電般快速、容錯的分散式搜尋引擎。它建立在**Lucene**之上,是一個高效能、功能齊全的全文搜尋引擎。
Solr 廣泛使用 ZooKeeper 的每個功能,例如配置管理、領導者選舉、節點管理、資料鎖定和同步。
Solr 有兩個不同的部分,**索引**和**搜尋**。索引是將資料儲存在適當格式的過程,以便以後可以搜尋。Solr 使用 ZooKeeper 來實現多個節點上的資料索引和多個節點上的搜尋。ZooKeeper 提供以下功能:
根據需要新增/刪除節點
節點之間的資料複製,從而最大程度地減少資料丟失
多個節點之間共享資料,從而從多個節點搜尋以獲得更快的搜尋結果
Apache Solr 的一些用例包括電子商務、職位搜尋等。