ZooKeeper 基礎知識、部署和應用程序

簡介

讓咱們首先討論一下爲何想使用 ZooKeeper。ZooKeeper 是一個面向分佈式系統的構建塊。當設計一個分佈式系統時,通常須要設計和開發一些協調服務:php

  • 名稱服務— 名稱服務是將一個名稱映射到與該名稱有關聯的一些信息的服務。電話目錄是將人的名字映射到其電話號碼的一個名稱服務。一樣,DNS 服務也是一個名稱服務,它將一個域名映射到一個 IP 地址。在分佈式系統中,您可能想跟蹤哪些服務器或服務在運行,並經過名稱查看其狀態。ZooKeeper 暴露了一個簡單的接口來完成此工做。也能夠將名稱服務擴展到組成員服務,這樣就能夠得到與正在查找其名稱的實體有關聯的組的信息。
  • 鎖定— 爲了容許在分佈式系統中對共享資源進行有序的訪問,可能須要實現分佈式互斥(distributed mutexes)。ZooKeeper 提供一種簡單的方式來實現它們。
  • 同步— 與互斥同時出現的是同步訪問共享資源的需求。不管是實現一個生產者-消費者隊列,仍是實現一個障礙,ZooKeeper 都提供一個簡單的接口來實現該操做。您能夠在 Apache ZooKeeper 維基上查看示例,瞭解如何作到這一點(參閱 參考資料)。
  • 配置管理— 您可使用 ZooKeeper 集中存儲和管理分佈式系統的配置。這意味着,全部新加入的節點都將在加入系統後就能夠當即使用來自 ZooKeeper 的最新集中式配置。這還容許您經過其中一個 ZooKeeper 客戶端更改集中式配置,集中地更改分佈式系統的狀態。
  • 領導者選舉— 分佈式系統可能必須處理節點停機的問題,您可能想實現一個自動故障轉移策略。ZooKeeper 經過領導者選舉對此提供現成的支持。

雖然能夠從頭開始設計和實現全部這些服務,但調試任何問題、競爭條件或死鎖都須要執行額外的工做,而且很難實現。就像您不會在代碼中隨處編寫本身的隨機數發生器或哈希函數同樣,這裏有一個要求:人們不該該在每次有須要時就處處從頭編寫本身的名稱服務或領導者選舉服務。此外,您能夠相對容易地一塊兒解決一個很是簡單的組成員服務,可是,要編寫它們來提供可靠性、複製和可擴展性,可能須要作更多的工做。這致使了 Apache ZooKeeper 的開發和開源,Apache ZooKeeper 是一個針對分佈式系統的、開箱即用的、可靠的、可擴展的、高性能的協調服務。html

InfoSphere® BigInsights™ Quick Start Edition 是 IBM 的大數據產品,以開源的 Apache Hadoop 項目爲基礎。它包括 ZooKeeper 和其餘大數據技術,以及增長了該平臺的價值的 IBM 技術。在本文中,咱們只是使用了 ZooKeeper,可是,如欲瞭解有關 InfoSphere BigInsights 的更多信息,請參閱 參考資料,其中包括一個下載產品的連接。java

ZooKeeper 雖然是一個針對分佈式系統的協調服務,但它自己也是一個分佈式應用程序。ZooKeeper 遵循一個簡單的客戶端-服務器模型,其中客戶端 是使用服務的節點(即機器),而服務器 是提供服務的節點。ZooKeeper 服務器的集合造成了一個 ZooKeeper 集合體(ensemble)。在任何給定的時間內,一個 ZooKeeper 客戶端可鏈接到一個 ZooKeeper 服務器。每一個 ZooKeeper 服務器均可以同時處理大量客戶端鏈接。每一個客戶端按期發送 ping 到它所鏈接的 ZooKeeper 服務器,讓服務器知道它處於活動和鏈接狀態。被詢問的 ZooKeeper 服務器經過 ping 確認進行響應,表示服務器也處於活動狀態。若是客戶端在指定時間內沒有收到服務器的確認,那麼客戶端會鏈接到集合體中的另外一臺服務器,並且客戶端會話會被透明地轉移到新的 ZooKeeper 服務器。node

圖 1 描述了 ZooKeeper 的客戶端-服務器架構。git

圖 1. ZooKeeper 的客戶端-服務器架構github

圖像顯示了 ZooKeeper 的客戶端-服務器架構

ZooKeeper 有一個相似於文件系統的數據模型,由 znodes 組成。能夠將 znodes(ZooKeeper 數據節點)視爲相似 UNIX 的傳統系統中的文件,但它們能夠有子節點。另外一種方式是將它們視爲目錄,它們能夠有與其相關的數據。每一個這些目錄都被稱爲一個 znode。圖 2 顯示的圖表明與兩個城市中的運動隊相同的層次結構。web

圖 2. 該圖表示了兩個城市中的運動隊的層次結構數據庫

圖像顯示了兩個城市中的運動隊的層次結構

znode 層次結構被存儲在每一個 ZooKeeper 服務器的內存中。這實現了對來自客戶端的讀取操做的可擴展的快速響應。每一個 ZooKeeper 服務器還在磁盤上維護了一個事務日誌,記錄全部的寫入請求。由於 ZooKeeper 服務器在返回一個成功的響應以前必須將事務同步到磁盤,因此事務日誌也是 ZooKeeper 中對性能最重要的組成部分。能夠存儲在 znode 中的數據的默認最大大小爲 1 MB。所以,即便 ZooKeeper 的層次結構看起來與文件系統類似,也不該該將它用做一個通用的文件系統。相反,應該只將它用做少許數據的存儲機制,以便爲分佈式應用程序提供可靠性、可用性和協調。apache

當客戶端請求讀取特定 znode 的內容時,讀取操做是在客戶端所鏈接的服務器上進行的。所以,因爲只涉及集合體中的一個服務器,因此讀取是快速和可擴展的。然而,爲了成功完成寫入操做,要求 ZooKeeper 集合體的嚴格意義上的多數節點都是可用的。在啓動 ZooKeeper 服務時,集合體中的某個節點被選舉爲領導者。當客戶端發出一個寫入請求時,所鏈接的服務器會將請求傳遞給領導者。此領導者對集合體的全部節點發出相同的寫入請求。若是嚴格意義上的多數節點(也被稱爲法定數量(quorum))成功響應該寫入請求,那麼寫入請求被視爲已成功完成。而後,一個成功的返回代碼會返回給發起寫入請求的客戶端。若是集合體中的可用節點數量未達到法定數量,那麼 ZooKeeper 服務將不起做用。安全

InfoSphere BigInsights Quick Start Edition

ZooKeeper 是 InfoSphere BigInsights(IBM 基於 Hadoop 的產品)中的一個組件。Quick Start Edition 是一個免費的、可下載的 InfoSphere BigInsights 版本。使用 Quick Start Edition,您能夠嘗試使用 ZooKeeper 和 IBM 開發的特性來提升開源 Hadoop 的價值,好比 Big SQL、文本分析和 BigSheets。引導式學習可以讓您的體驗儘量地順暢,包括循序漸進、自訂進度的教程和視頻,可幫助您開始讓 Hadoop 爲您所用。沒有時間或數據限制,您能夠自行安排時間,在大量數據上試驗。請 觀看視頻學習教程(PDF) 和 馬上下載 BigInsights Quick Start Edition

法定數量是經過嚴格意義上的多數節點來表示的。在集合體中,能夠包含一個節點,但它不是一個高可用和可靠的系統。若是在集合體中有兩個節點,那麼這兩個節點都必須已經啓動並讓服務正常運行,由於兩個節點中的一個並非嚴格意義上的多數。若是在集合體中有三個節點,即便其中一個停機了,您仍然能夠得到正常運行的服務(三個中的兩個是嚴格意義上的多數)。出於這個緣由,ZooKeeper 的集合體中一般包含奇數數量的節點,由於就容錯而言,與三個節點相比,四個節點並不佔優點,由於只要有兩個節點停機,ZooKeeper 服務就會中止。在有五個節點的集羣上,須要三個節點停機纔會致使 ZooKeeper 服務中止運做。

如今,咱們已經清楚地瞭解到,節點數量應該是奇數,讓咱們再來思考一下 ZooKeeper 集合體中須要有多少個節點。讀取操做始終從鏈接到客戶端的 ZooKeeper 服務器讀取數據,因此它們的性能不會隨着集合體中的服務器數量額變化而變化。可是,僅在寫入法定數量的節點時,寫入操做纔是成功的。這意味着,隨着在集合體中的節點數量的增長,寫入性能會降低,由於必須將寫入內容寫入到更多的服務器中,並在更多服務器之間進行協調。

ZooKeeper 的美妙之處在於,想運行多少服務器徹底由您本身決定。若是想運行一臺服務器,從 ZooKeeper 的角度來看是沒問題的;只是您的系統再也不是高度可靠或高度可用的。三個節點的 ZooKeeper 集合體支持在一個節點故障的狀況下不丟失服務,這對於大多數用戶而言,這多是沒問題的,也能夠說是最多見的部署拓撲。不過,爲了安全起見,能夠在您的集合體中使用五個節點。五個節點的集合體讓您能夠拿出一臺服務器進行維護或滾動升級,並可以在不中斷服務的狀況下承受第二臺服務器的意外故障。

所以,在 ZooKeeper 集合體中,3、五或七是最典型的節點數量。請記住,ZooKeeper 集合體的大小與分佈式系統中的節點大小沒有什麼關係。分佈式系統中的節點將是 ZooKeeper 集合體的客戶端,每一個 ZooKeeper 服務器都可以以可擴展的方式處理大量客戶端。例如,HBase(Hadoop 上的分佈式數據庫)依賴​​於 ZooKeeper 實現區域服務器的領導者選舉和租賃管理。您能夠利用一個相對較少(好比說,五個)節點的 ZooKeeper 集合體運行有 50 個節點的大型 HBase 集羣。

設置並部署 ZooKeeper 集合體

如今讓咱們設置並部署有三個節點的 ZooKeeper 集合體。在這裏,咱們將使用撰寫本文時的最新版的 ZooKeeper:3.4.5(請參閱 參考資料 得到有關的下載信息)。咱們用於此演示的節點被命名爲 zkserver1.mybiz.com、zkserver2.mybiz.com 和 zk3server3.mybiz.com。必須在每一個節點上遵循下面的步驟來啓動 ZooKeeper 服務器:

  1. 若是還沒有安裝 JDK,請下載安裝它(參閱 參考資料)。這是必需的,由於 ZooKeeper 服務器在 JVM 上運行。
  2. 下載 ZooKeeper 3.4.5. tar.gz tarball 並將它解壓縮到適當的位置。

    清單 1. 下載 ZooKeeper tarball 並將它解壓縮到適當的位置

    1

    2

    3

    wget

    http://www.bizdirusa.com/mirrors/apache/ZooKeeper/stable/zookeeper3.4.5.

    tar.gz tar xzvf zookeeper3.4.5.tar.gz

  3. 建立一個目錄,用它來存儲與 ZooKeeper 服務器有關聯的一些狀態:mkdir /var/lib/zookeeper。您可能須要將這個目錄建立爲根目錄,並在之後將這個目錄的全部者更改成您但願運行 ZooKeeper 服務器的用戶。
  4. 設置配置。建立或編輯 zookeeper3.4.5/conf/zoo.cfg 文件,使其與 清單 2 類似。

    清單 2. 設置配置

    1

    2

    3

    4

    5

    6

    tickTime=2000

    dataDir=/var/lib/zookeeper clientPort=2181

    initLimit=5 syncLimit=2

    server.1=zkserver1.mybiz.com:2888:3888

    server.2=zkserver2.mybiz.com:2888:3888

    server.3=zkserver3.mybiz.com:2888:3888


    值得重點注意的一點是,全部三個機器都應該打開端口 218一、2888 和 3888。在本例中,端口 2181 由 ZooKeeper 客戶端使用,用於鏈接到 ZooKeeper 服務器;端口 2888 由對等 ZooKeeper 服務器使用,用於互相通訊;而端口 3888 用於領導者選舉。您能夠選擇本身喜歡的任何端口。一般建議在全部 ZooKeeper 服務器上使用相同的端口。
  5. 建立一個 /var/lib/zookeeper/myid 文件。此文件的內容將只包含 zkserver1.mybiz.com 上的數字 一、zkserver2.mybiz.com 上的數字 2 和 zkserver3.mybiz.com 上的數字 3。清單 3 顯示了來自 zkserver1.mybiz.com 的此文件的 cat 輸出。

    清單 3. cat 輸出

    1

    2

    mark@zkserver1.mybiz.com:~# cat

    /var/lib/zookeeper/myid 1


    如今,您已經作好了在每臺機器上啓動 ZooKeeper 服務器的準備。

    清單 4. 啓動 ZooKeeper 服務器

    1

    2

    zookeeper3.4.5/ bin/zkServer.sh

    start


    如今,您能夠從其中一臺正在運行 ZooKeeper 服務器的機器上啓動一個 CLI 客戶端。

    清單 5. 啓動 CLI 客戶端

    1

    2

    zookeeper3.4.5/ bin/zkCli.sh server

    zkserver1.mybiz.com:2181,zkserver2.mybiz.com:2181,zkserver3.mybiz.com:2181


    客戶端提供一個服務器列表,能夠任意選中一個進行鏈接。若是在鏈接過程當中失去與該服務器的鏈接,則會選中列表中的另外一臺服務器,並且客戶端會話也會轉移到該服務器。一旦啓動了客戶端,您就能夠建立、編輯和刪除 znode。讓咱們在 /mynode 建立一個znode,使用 helloworld 做爲關聯的數據。

    清單 6. 在 /mynode 上建立一個 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 2] create /mynode

    helloworld Created /mynode


    如今,讓咱們在 /mynode 驗證和檢索數據。

    清單 7. 在 /mynode 驗證和檢索數據

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED) 6] get /mynode

    helloworld cZxid = 0x200000005 ctime = Sat Jul 20

    19:53:52 PDT 2013 mZxid = 0x200000005 mtime = Sat

    Jul 20 19:53:52 PDT 2013 pZxid = 0x200000005

    cversion = 0 dataVersion = 0 aclVersion = 0

    ephemeralOwner = 0x0 dataLength = 11 numChildren =

    0


    您會發現,在獲取一個 znode 數據時,客戶端也返回了一些與 znode 有關的元數據。此元數據中的一些重要字段包括,與建立和最後修改 znode 的時間有關的階段時間戳(ctime 和 mtime)、每次修改數據都會更改的數據版本(dataVersion)、數據長度(dataLength)、這個 znode 的子節點的數量(numChildren)。咱們如今能夠刪除 znode。

    清單 8. 刪除 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 7]

    rmr /mynode


    讓咱們在 /mysecondnode 建立另外一個 znode。

    清單 9. 建立另外一個 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 10] create

    /mysecondnode hello Created /mysecondnode


    如今,讓咱們在 /mysecondnode 驗證和檢索數據。這一次,咱們在最後提供了一個可選參數 1。此參數爲 /mysecondnode 上的數據設置了一個一次性的觸發器(名稱爲 watch)。若是另外一個客戶端在 /mysecondnode 上修改數據,該客戶端將會得到一個異步通知。請注意,該通知只發送一次,除非 watch 被從新設置,不然不會因數據發生改變而再次發送通知。

    清單 10. 在 /mysecondnode 上驗證和檢索數據

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED) 12] get

    /mysecondnode 1 hello cZxid = 0x200000007 ctime =

    Sat Jul 20 19:58:27 PDT 2013 mZxid = 0x200000007

    mtime = Sat Jul 20 19:58:27 PDT 2013 pZxid =

    0x200000007 cversion = 0 dataVersion = 0

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 5

    numChildren = 0


    如今,從不一樣的客戶端(好比,從不一樣的機器)更改與 /mysecondnode 有關聯的數據的值。

    清單 11. 更改與 /mysecondnode 有關聯的數據的值

    1

    2

    3

    4

    5

    6

    7

    [zk: localhost:2181(CONNECTED)

    1] set /mysecondnode hello2 cZxid = 0x200000007

    ctime = Sat Jul 20 19:58:27 PDT 2013 mZxid =

    0x200000009 mtime = Sat Jul 20 20:02:37 PDT 2013

    pZxid = 0x200000007 cversion = 0 dataVersion = 1

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6

    numChildren = 0


    您會發現,在第一個客戶端上得到了一個 watch 通知。

    清單 12. 在第一個客戶端上得到了一個 watch 通知

    1

    2

    3

    [zk:127.0.0.1:2181(CONNECTED) 13] WATCHER::

    WatchedEvent state:SyncConnected

    type:NodeDataChanged path:/mysecondnode


    繼續下去,由於 znode 造成了一個分層命名空間,因此您還能夠建立子節點。 

    清單 13. 建立子節點

    1

    2

    3

    [zk:

    localhost:2181(CONNECTED) 2] create /mysecondnode/

    subnode 123 Created /mysecondnode/ subnode


    您能夠得到關於某個 znode 的其餘統計元數據。 

    清單 14. 得到關於某個 znode 的其餘統計元數據

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED)

    14] stat /mysecondnode cZxid = 0x200000007 ctime =

    Sat Jul 20 19:58:27 PDT 2013 mZxid = 0x200000009

    mtime = Sat Jul 20 20:02:37 PDT 2013 pZxid =

    0x20000000a cversion = 1 dataVersion = 1

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6

    numChildren = 1

在上面的示例中,咱們使用了 ZooKeeper 的 CLI 客戶端與 ZooKeeper 服務器進行交互。ZooKeeper 提供了 Java™、C、Python 和其餘綁定。您能夠經過這些綁定調用客戶端 API,將 Java、C 或 Python 應用程序轉換爲 ZooKeeper 客戶端。

ZooKeeper 的應用程序

因爲 ZooKeeper 在分佈式系統中提供了一些多功能的用例,ZooKeeper 有一組不一樣的實用應用程序。咱們將在這裏列出部分這些應用程序。這些應用程序大多取自 Apache ZooKeeper 維基,那裏還提供了一個更完整的最新列表。請參閱 參考資料,得到這些技術的連接:

  • Apache Hadoop 依靠 ZooKeeper 來實現 Hadoop HDFS NameNode 的自動故障轉移,以及 YARN ResourceManager 的高可用性。
  • Apache HBase 是構建於 Hadoop 之上的分佈式數據庫,它使用 ZooKeeper 來實現區域服務器的主選舉(master election)、租賃管理以及區域服務器之間的其餘通訊。
  • Apache Accumulo 是構建於 Apache ZooKeeper(和 Apache Hadoop)之上的另外一個排序分佈式鍵/值存儲。
  • Apache Solr 使用 ZooKeeper 實現領導者選舉和集中式配置。
  • Apache Mesos 是一個集羣管理器,提供了分佈式應用程序之間高效的資源隔離和共享。Mesos 使用 ZooKeeper 實現了容錯的、複製的主選舉。
  • Neo4j 是一個分佈式圖形數據庫,它使用 ZooKeeper 寫入主選擇和讀取從協調(read slave coordination)。
  • Cloudera Search 使用 ZooKeeper(經過 Apache Solr)集成了搜索功能與 Apache Hadoop,以實現集中式配置管理。

結束語

實現您本身的協議來協調分佈式系統,這多是一個使人感到沮喪的費時的過程。這正是 ZooKeeper 發揮其做用的地方。ZooKeeper 是一個穩定的、簡單的、高性能的協調服務,爲您提供編寫正確的分佈式應用程序所需的工具,而無需擔憂競爭條件、死鎖和不一致。在下一次編寫分佈式應用程序時,您就能夠利用 ZooKeeper 支持全部協調需求。

相關主題

相關文章
相關標籤/搜索