一、Zookeeper 概述(官網翻譯)
ZooKeeper 通過一個可共享的分層數據註冊(稱之爲znode)命名空間來協調分佈部署的各個進程,這與文件系統很相像。與一般的文件不同,ZooKeeper提供給客戶端的服務是高吞吐、低延遲、高可用和嚴格有序的。性能上的特點使得ZooKeeper常被用於大規模分佈式集羣。它的高可靠性使得它能夠避免大型系統中常見的單點故障。嚴格有序的特點使得客戶端可以實現複雜的同步邏輯。
ZooKeeper的命名空間非常像一個標準文件系統。每個名稱都是用“/”分隔的一系列路徑。每個znode都被用一個路徑標示,每個路徑都以“/”也就是根路徑開始。與標準文件系統很相似,當znode還有子路徑的時候不能夠被刪除。
ZooKeeper與標準文件系統最主要的不同是數據存儲在多個znode節點上,每個znode節點上存放的數據是有限的。設計ZooKeeper的目的是存儲元數據,例如狀態信息,配置,位置信息等等。這些元數據通常是Kbytes級別的。ZooKeeper有一個檢查機制來避免存儲大於1m的文件,不過一般存儲的數據大小都小於這個值。
ZooKeeper的服務可以由多臺機器提供。這些機器共同維護着一個存在內存中的數據樹形結構,還有事務日誌以及持久化的快照。因爲數據保存在內存中,所以ZooKeeper才能做到高吞吐和低延遲。但是這也有一個缺點就是它能管理的數據大小受制於內存。這也就是爲什麼要限制znode上存儲的數據量的深層次原因。
組成ZooKeeper的每個節點都要知道集羣中其他節點的信息。只要大多數節點是可用的,整個服務就可用。客戶端也需要保留一份節點列表,並用這個來使用ZooKeeper服務。
客戶端在一個時間只會連接一個節點。它通過建立一個TCP連接來發送請求,獲取響應,得到事件通知和發送心跳信息。假如這個TCP連接中斷了,客戶端會重新連接另一個節點。ZooKeeper服務會在客戶端第一次連接到它的時候在客戶端所連接到的節點上開啓一個會話。如果客戶端需要連接另一個節點,這個會話會被新節點重置。
客戶端發出的讀請求由它所連接的那個節點處理。假如讀請求在某個znode註冊了一個監視事件,這個監視也由這個節點來負責。寫請求會被髮給多個節點,在所有節點都完成之後纔會返回響應,這是爲了保證一致性。同步請求也會被髮送給多個節點,但是不保證一致性。因此讀操作的吞吐能力會隨着節點的數目增多而增加,但是寫吞吐能力卻會下降。
對於ZooKeeper順序很重要。因此它用了強制性措施來保證有序。所有的更新都是統一有序的。ZooKeeper會給每個更新一個序號,稱之爲zxid(ZooKeeper Transaction Id)。每次更新的zxid都是唯一的。讀操作是相對於寫有序的。讀請求的響應會被所請求的服務器標記上它(這臺服務器)所處理的最後一個zxid。
二、zookeeper的數據模型
Zookeeper 會維護一個具有層次關係的數據結構,它非常類似於一個標準的文件系統,如圖所示:
zookeeper的數據結構具有如下特點:
- 每個子目錄項如 NameService 都被稱作爲 znode,這個 znode 是被它所在的路徑唯一標識,如 Server1 這個 znode 的標識爲 /NameService/Server1。如果創建與一個已經存在的路徑標示相同標示的節點,則會報錯。
- znode 可以有子節點目錄,並且每個 znode 可以存儲數據,存儲的數據需要小於1M。
- znode 是有版本的,每個 znode 中存儲的數據可以有多個版本,也就是一個訪問路徑中可以存儲多份數據
- znode 可以是臨時節點,一旦創建這個 znode 的客戶端與服務器失去聯繫,這個 znode 也將自動刪除,Zookeeper 的客戶端和服務器通信採用長連接方式,每個客戶端和服務器通過心跳來保持連接,這個連接狀態稱爲 session,如果 znode 是臨時節點,這個 session 失效,znode 也就刪除了
- znode 的目錄名可以自動編號,如 App1 已經存在,再創建的話,將會自動命名爲 App2
- znode 可以被監控,包括這個目錄節點中存儲的數據的修改,子節點目錄的變化等,一旦變化可以通知設置監控的客戶端,這個是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基於這個特性實現的。
- 一個znode存在子節點,那麼對這個znode刪除操作會不成功,及每次刪除只能刪除葉子節點。
三、如何保證zookeeper集羣每臺機器上的數據的一致性
四、zookeeper的部署以及客戶端代碼的編寫
tickTime=2000 dataDir=../devtools/zookeeper-3.2.2/build clientPort=2181
- tickTime:這個時間是作爲 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳
- dataDir:顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日誌文件也保存在這個目錄裏。
- clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。
當這些配置項配置好後,你現在就可以啓動 Zookeeper 了,啓動後要檢查 Zookeeper 是否已經在服務,可以通過 netstat – ano 命令查看是否有你配置的 clientPort 端口號在監聽服務。
2. 集羣模式:Zookeeper 的集羣模式的安裝和配置也不是很複雜,所要做的就是增加幾個配置項。集羣模式除了上面的三個配置項還要增加下面幾個配置項:
initLimit=5 syncLimit=2 server.1=192.168.211.1:2888:3888 server.2=192.168.211.2:2888:3888
- initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這裏所說的客戶端不是用戶連接 Zookeeper 服務器的客戶端,而是 Zookeeper 服務器集羣中連接到 Leader 的 Follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數。當已經超過 10 個心跳的時間(也就是 tickTime)長度後 Zookeeper 服務器還沒有收到客戶端的返回信息,那麼表明這個客戶端連接失敗。總的時間長度就是 5*2000=10 秒
- syncLimit:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 2*2000=4 秒
- server.A=B:C:D:其中 A 是一個數字,表示這個是第幾號服務器;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集羣中的 Leader 服務器交換信息的端口;D 表示的是萬一集羣中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。如果是僞集羣的配置方式,由於 B 都是一樣,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號。
除了修改 zoo.cfg 配置文件,集羣模式下還要配置一個文件 myid,這個文件在 dataDir 目錄下,這個文件裏面就有一個數據就是 A 的值,Zookeeper 啓動時會讀取這個文件,拿到裏面的數據與 zoo.cfg 裏面的配置信息比較從而判斷到底是那個 server。
詳細可參考:Zookeeper集羣環境安裝過程詳解