ZooKeeper 快速指南



ZooKeeper - 概述

ZooKeeper 是一種分散式協調服務,用於管理大量主機。在分散式環境中協調和管理服務是一個複雜的過程。ZooKeeper 透過其簡單的架構和 API 解決了這個問題。ZooKeeper 允許開發人員專注於核心應用程式邏輯,而無需擔心應用程式的分散式特性。

ZooKeeper 框架最初是在“雅虎!”構建的,用於以簡單而可靠的方式訪問其應用程式。後來,Apache ZooKeeper 成為 Hadoop、HBase 和其他分散式框架使用的標準化服務。例如,Apache HBase 使用 ZooKeeper 來跟蹤分散式資料的狀態。

在繼續之前,瞭解一些關於分散式應用程式的資訊非常重要。因此,讓我們從分散式應用程式的快速概述開始討論。

分散式應用程式

分散式應用程式可以在網路中的多個系統上同時執行,透過相互協調以快速有效的方式完成特定任務。通常,複雜且耗時的任務(非分散式應用程式(在單個系統中執行)可能需要數小時才能完成)可以透過分散式應用程式在幾分鐘內完成,因為它利用了所有參與系統的計算能力。

透過將分散式應用程式配置為在更多系統上執行,可以進一步減少完成任務的時間。執行分散式應用程式的一組系統稱為**叢集**,叢集中執行的每臺機器稱為**節點**。

分散式應用程式有兩個部分:**伺服器**和**客戶端**應用程式。伺服器應用程式實際上是分散式的,並且具有公共介面,以便客戶端可以連線到叢集中的任何伺服器並獲得相同的結果。客戶端應用程式是與分散式應用程式互動的工具。

Distributed Application

分散式應用程式的優勢

  • **可靠性** - 單個或少數幾個系統的故障不會導致整個系統故障。

  • **可擴充套件性** - 可以根據需要透過新增更多機器來提高效能,只需對應用程式進行少量配置更改,並且無需停機。

  • **透明性** - 隱藏系統的複雜性,並顯示為單個實體/應用程式。

分散式應用程式的挑戰

  • **競爭條件** - 兩臺或多臺機器嘗試執行特定任務,而該任務實際上在任何給定時間只能由一臺機器執行。例如,共享資源在任何給定時間只能由一臺機器修改。

  • **死鎖** - 兩臺或多臺操作無限期地等待彼此完成。

  • **不一致性** - 資料的部分故障。

Apache ZooKeeper 的用途是什麼?

Apache ZooKeeper 是一種由叢集(節點組)使用的服務,用於在它們之間進行協調並使用強大的同步技術維護共享資料。ZooKeeper 本身就是一個分散式應用程式,提供編寫分散式應用程式的服務。

ZooKeeper 提供的常見服務如下:

  • **命名服務** - 透過名稱識別叢集中的節點。它類似於 DNS,但用於節點。

  • **配置管理** - 為加入的節點提供系統最新和最新的配置資訊。

  • **叢集管理** - 節點加入/離開叢集以及即時節點狀態。

  • **Leader 選舉** - 選舉一個節點作為協調目的的領導者。

  • **鎖定和同步服務** - 在修改資料時鎖定資料。此機制有助於在連線其他分散式應用程式(如 Apache HBase)時實現自動故障恢復。

  • **高可靠性資料登錄檔** - 即使一個或幾個節點出現故障,也能保證資料的可用性。

分散式應用程式提供了許多好處,但也帶來了一些複雜且難以解決的挑戰。ZooKeeper 框架提供了一種完整的機制來克服所有這些挑戰。競爭條件和死鎖使用**故障安全同步方法**處理。另一個主要缺點是不一致的資料,ZooKeeper 透過**原子性**解決了這個問題。

ZooKeeper 的優勢

以下是使用 ZooKeeper 的優勢:

  • 簡單的分散式協調過程

  • **同步** - 伺服器程序之間的互斥和協作。此過程有助於 Apache HBase 進行配置管理。

  • 有序訊息

  • **序列化** - 根據特定規則編碼資料。確保您的應用程式一致執行。此方法可用於 MapReduce 協調佇列以執行正在執行的執行緒。

  • 可靠性

  • **原子性** - 資料傳輸要麼完全成功,要麼完全失敗,但沒有部分事務。

ZooKeeper - 基礎知識

在深入研究 ZooKeeper 的工作原理之前,讓我們先了解一下 ZooKeeper 的基本概念。我們將在本章中討論以下主題:

  • 架構
  • 分層名稱空間
  • 會話
  • 監視器

ZooKeeper 的架構

請檢視下圖。它描述了 ZooKeeper 的“客戶端-伺服器架構”。

Architecture of ZooKeeper

ZooKeeper 架構中每個元件都在下表中進行了說明。

部分 描述
客戶端

客戶端(我們分散式應用程式叢集中的節點之一)從伺服器訪問資訊。在特定時間間隔內,每個客戶端都會向伺服器傳送一條訊息,以告知伺服器客戶端處於活動狀態。

同樣,伺服器在客戶端連線時會發送確認。如果從連線的伺服器沒有響應,客戶端會自動將訊息重定向到另一個伺服器。

伺服器 伺服器(我們 ZooKeeper 叢集中的節點之一)為客戶端提供所有服務。向客戶端傳送確認以告知伺服器處於活動狀態。
叢集 ZooKeeper 伺服器組。形成叢集所需的最小節點數為 3。
領導者 伺服器節點,如果任何連線的節點發生故障,則執行自動恢復。領導者在服務啟動時選舉產生。
跟隨者 遵循領導者指令的伺服器節點。

分層名稱空間

下圖描述了用於記憶體表示的 ZooKeeper 檔案系統的樹結構。ZooKeeper 節點稱為**znode**。每個 znode 都由一個名稱標識,並由路徑序列(/)分隔。

  • 在圖中,首先有一個根**znode**,由“/”分隔。在根目錄下,有兩個邏輯名稱空間**config**和**workers**。

  • **config**名稱空間用於集中式配置管理,而**workers**名稱空間用於命名。

  • 在**config**名稱空間下,每個 znode 可以儲存最多 1MB 的資料。這類似於 UNIX 檔案系統,只是父 znode 也可以儲存資料。此結構的主要目的是儲存同步資料並描述 znode 的元資料。此結構稱為**ZooKeeper 資料模型**。

Hierarchical Namespace

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 的工作流程,後續表格解釋了其不同的元件。

ZooKeeper Ensemble
元件 描述
寫入 寫入過程由領導者節點處理。領導者節點將寫入請求轉發到所有 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並新增一個方法connectconnect方法建立一個 ZooKeeper 物件,連線到 ZooKeeper 叢集,然後返回該物件。

這裡CountDownLatch用於停止(等待)主程序,直到客戶端與 ZooKeeper 叢集連線。

ZooKeeper 叢集透過Watcher 回撥回覆連線狀態。一旦客戶端與 ZooKeeper 叢集連線,Watcher 回撥將被呼叫,並且 Watcher 回撥呼叫CountDownLatchcountDown方法來釋放鎖,主程序中的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。現在,使用自定義pathdata呼叫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 的一些用例包括電子商務、職位搜尋等。

廣告

© . All rights reserved.