Zookeeper簡介
zookeeper是一個爲分佈式應用所設計的開源協調服務,提供同步,配置管理,分組和命名服務。
設計目標:
- 簡單化
zookeeper允許分佈式的進程通過共享體系內的命名空間來進行協調,其組織與標準的文件系統非常相似,是由一些數據寄存器組成,在zookeeper中,這些寄存器稱之爲znode。zookeeper的數據存放在內存當中,因此其具有高吞吐量和低延遲。 - 健壯性
zookeeper維護着一個處於內存中的狀態鏡像,一個位於存儲器中的交換日誌和快照。只要大部分服務器可用,那麼zookeeper服務就是可用的。服務器與客戶端之間通過TCP連接,並通過TCP連接來發送請求,獲得相應,獲取檢測事件及發送心跳。 - 有序性
zookeeper可以爲每一次更新操作賦予一個版本號,且此版本號全局有效,不存在重複情況。 - 速度優勢
zookeeper在讀取主要負載的時候,特別快,當讀工作比寫工作多的時候,執行性能更好。
zookeeper的命名空間
zookeeper的命名空間與標準的文件系統比較相似,是通過斜線分隔的路徑名序列組成。
zookeeper的數據模型
zookeeper具有分層的命名空間,每個節點可以有數據關聯作爲他們的子節點,就如一個文件系統允許文件作爲目錄或目錄可以存放數據。
znode:zookeeper節點
zookeeper樹形結構中,每個節點都可以稱之爲znode,znode維護着一個屬性結構,它包含數據的版本號,時間戳等狀態信息。
znode的特徵
- Watches
客戶端在節點上設置watch(監視器),當節點的狀態發生改變,將會觸發watch對應的操作。當watch被觸發時,zookeeper將會向客戶端發送且僅發送一個通知,因爲watch只能被觸發一次。 - 數據訪問
znode具有原子性,每一個znode的數據將被原子地讀寫。讀取數據的時候,將讀取與znode相關的所有數據,寫操作將替換掉所有的數據,每個節點都擁有自己的ACL。 - 臨時節點
zookeeper中節點分爲兩種,臨時和永久,節點類型在創建之初即被確定,不能改變。臨時節點依賴於當前的會話,會話結束,臨時節點將被刪除。 - 順序節點(唯一性保證)
父節點會爲第一個子節點維護一份記錄,會記錄每個子節點創建的先後順序。
zookeeper中的時間
zk中有多種時間記錄的形式,其中包括:
- Zxid
對節點狀態改變的每一個操作,都將使節點收到一個zxid格式的時間戳,且時間戳全局有序。 - 版本號
對節點的每一個操作,都將使節點版本號增加,每個節點維護三個版本號:version(節點數據版本號),cversion(子節點版本號),aversion(節點所擁有的ACL版本號)。
zookeeper會話狀態
zk客戶端通過zk服務器建立一個會話,當連接成功,則狀態變爲CONNECTED,一般只有兩種狀態,CONNECTED和CLOSED。
zookeeper狀態轉換圖:
zookeeper的一致性保證
- 順序一致性
客戶端的更新順序與他們被髮送的順序相一致。 - 原子性
更新操作要麼成功,要麼失敗,沒有第三種結果。 - 單系統鏡像
無論客戶端連接到哪一個服務器,他將看到相同的zk視圖 - 可靠性
一旦一個更新操作被應用,那麼客戶端再次更新之前,某值將不會改變。
- 客戶端成功獲取正確的返回代碼,則表名更新已成功,不能夠獲得返回代碼,那麼客戶端將無法知道更新操作是否成功。
- 故障恢復時,任何客戶端都能夠看到的執行成功的更新操作將不會回滾。
- 實時性
在特定時間內,客戶端看到系統需要被保證是實時的(在十幾秒的時間裏)。在此時間段內,任何系統的改變將被客戶端看到的,或者被客戶端則測到。
zookeeper鎖服務
zookeeper加鎖方式:
- 客戶端調用create()方法,創建“locknode/lock-”連續的臨時節點,此節點爲類型爲sequence(連續)和ephemeral(臨時)。也就是說,創建的節點爲臨時節點,並且所有的節點連續編號,即爲“lock-i”的格式。
- 在創建的鎖節點上調用getChildren()方法,以獲取鎖目錄下的最小編號節點,並且不設置watch。
- 若步驟2中獲取的節點恰好是步驟1中客戶端創建的節點,那麼此客戶端會獲得該種類型的鎖,然後退出操作。
- 客戶端在鎖目錄上調用exists()方法,並且設置watch來監視鎖目錄下序號相對自己次小的連續臨時節點的狀態變化。
- 如果監視節點狀態發生變化,則跳轉到步驟2,繼續進行後續的操作,直到退出鎖競爭。
zookeeper的鎖機制流程如圖: