最近在學習zookeeper,發現zk真的是一個優秀的中介軟體。在分散式環境下,可以高效解決資料管理問題。在學習的過程中,要深入zk的工作原理,並根據其特性做一些簡單的分散式環境下資料管理工具。本文首先對zk的工作原理和相關概念做一下介紹,然後帶大家做一個簡單的分散式配置中心。
zookeeper介紹
zookeeper是一個分散式協調框架,主要是解決分散式應用中經常遇到的一些資料管理問題,如:統一命名服務、狀態同步服務、叢集管理、分散式應用配置項的管理、分散式鎖等。
zookeeper使用
檢視節點
# ls /path
建立節點
#create /path data
修改節點
#set /path data
刪除節點
#delete /path
獲取節點資料
#get /path
zookeeper C/S連線狀態
1)KeeperState.Expired:客戶端和伺服器在ticktime的時間週期內,是要傳送心跳通知的。這是租約協議的一個實現。客戶端傳送request,告訴伺服器其上一個租約時間,伺服器收到這個請求後,告訴客戶端其下一個租約時間是哪個時間點。當客戶端時間戳達到最後一個租約時間,而沒有收到伺服器發來的任何新租約時間,即認為自己下線(此後客戶端會廢棄這次連線,並試圖重新建立連線)。這個過期狀態就是Expired狀態
2)KeeperState.Disconnected:就像上面那個狀態所述,當客戶端斷開一個連線(可能是租約期滿,也可能是客戶端主動斷開)這是客戶端和伺服器的連線就是Disconnected狀態
3)KeeperState.SyncConnected:一旦客戶端和伺服器的某一個節點建立連線(注意,雖然叢集有多個節點,但是客戶端一次連線到一個節點就行了),並完成一次version、zxid的同步,這時的客戶端和伺服器的連線狀態就是SyncConnected
4)KeeperState.AuthFailed:ookeeper客戶端進行連線認證失敗時,發生該狀態
zookeeper工作原理
檔案系統 + 監聽機制
檔案系統特點
同一個目錄下檔名稱不能重複,同樣zookeeper也是這樣的,zookeeper中統一叫作znode。znode節點可以包含子znode,也可以同時包含資料。znode只適合儲存非常小的資料,不能超過1M,最好都小於1K。
znode節點型別
臨時節點(EPHEMERAL):客戶端關閉zk連線後清除
永久節點(persistent):持久化節點,除非客戶端主動刪除
有編號節點(Persistent_sequential):自動增加順序編號的znode持久化節點
臨時有編號(Ephemral_ sequential):臨時自動編號設定,znode節點編號會自動增加,但是會客戶端連線斷開而消失。分散式鎖用的是這個型別的節點。
注:EPHEMERAL 臨時型別的節點不能有子節點,對於zk來說,有幾個節點資料就會儲存幾份。
監聽機制
客戶端註冊監聽它關心的目錄節點,當目錄節點發生變化(資料改變、節點刪除、子目錄節 點增加刪除)時,zookeeper會通知客戶端。
1、客戶端啟動時向zookeeper伺服器註冊資訊
2、客戶端啟動同時註冊一系列的Watcher型別的監聽器到本地的WatchManager中
3、zookeeper伺服器中節點發生變化後,觸發watcher事件後通知給客戶端,客戶端執行緒從WatcherManager中取出對應的Watcher物件來執行回撥邏輯。
zookeeper監聽的事件型別
EventType.NodeCreated:當znode節點被建立時,該事件被觸發。
EventType.NodeChildrenChanged:當znode節點的直接子節點被建立、被刪除、子節點資料發生變更時,該事件被觸發。
EventType.NodeDataChanged:當znode節點的資料發生變更時,該事件被觸發。
EventType.NodeDeleted:當znode節點被刪除時,該事件被觸發。
EventType.None:當zookeeper客戶端的連線狀態發生變更時,即KeeperState.Expired、KeeperState.Disconnected、KeeperState.SyncConnected、KeeperState.AuthFailed狀態切換時,描述的事件型別為EventType.None。
zookeeper下server工作狀態
LOOKING:當前server不知道leader是誰,正在選舉
LEADING:當前server即為選舉出來的leader
FOLLOWING:leader已經選舉出來,當前server是follower
ZAB協議
ZAB 協議全稱:Zookeeper Atomic Broadcast(Zookeeper 原子廣播協議)。
ZAB 協議作用:解決分散式資料管理一致性。
ZAB 協議定義:ZAB 協議是為分散式協調服務 Zookeeper 專門設計的一種支援 崩潰恢復 和 訊息廣播 協議。
基於該協議,Zookeeper 實現了一種 主備模式 的系統架構來保持叢集中各個副本之間資料一致性。
訊息廣播
zookeeper叢集採用主從(leader-follower)模式保證服務高可用。leader節點可讀可寫,follower節點只讀,這種模式就需要保證leader節點和follower節點的資料一致性。對於客戶端傳送的寫請求,全部由 Leader 接收,Leader 將請求封裝成一個事務 Proposal,將其傳送給所有 Follwer ,然後,根據所有 Follwer 的反饋,如果超過半數成功響應,則執行 commit 操作(先提交自己,再傳送 commit 給所有 Follwer)。
注:上述中有一個概念:兩階段提交過程(分散式系統中資料一致性經常會涉及到的方案)。follower節點是可以處理寫請求的,會轉發給leader節點。leader節點通過訊息廣播(二階段提交)同步寫操作到follower節點,保證資料一致性。
zookeeper中每個事務都對應一個ZXID(全域性的、唯一的、順序的)。ZXID 是一個 64 位的數字,其中低 32 位可以看作是一個簡單的遞增的計數器,針對客戶端的每一個事務請求,Leader 都會產生一個新的事務 Proposal 並對該計數器進行 + 1 操作。而高 32 位則代表了 Leader 伺服器上取出本地日誌中最大事務 Proposal 的 ZXID,並從該 ZXID 中解析出對應的 epoch 值,然後再對這個值加一。
崩潰恢復
即如果在訊息廣播的過程中,leader死掉了,如何保證資料的一致性問題。
假設兩種異常情況:
1、一個事務在 Leader 上提交了,並且過半的 Folower 都響應 Ack 了,但是 Leader 在 Commit 訊息發出之前掛了。
2、假設一個事務在 Leader 提出之後,Leader 掛了。
考慮到上述兩種異常情況,Zab 協議崩潰恢復要求滿足以下兩個要求:
1)確保已經被 Leader 提交的 Proposal 必須最終被所有的 Follower 伺服器提交。
2)確保丟棄已經被 Leader 提出的但是沒有被提交的 Proposal。
崩潰恢復主要包含:leader選舉 和 資料恢復。
leader選舉:
1、要求 可用節點數量 > 總節點數量/2 。注意 是 > , 不是 ≥。
2、新選舉出來的 Leader 不能包含未提交的 Proposal(新選舉的 Leader 必須都是已經提交了 Proposal 的 Follower 伺服器節點) 、新選舉的 Leader 節點中含有最大的 zxid(可以避免 Leader 伺服器檢查 Proposal 的提交和丟棄工作。如果zxid相同,選擇server_id【zoo.cfg中的myid】最大的。)
資料恢復:
1、上面講過了ZXID的高 32 位代表了每代 Leader 的唯一性,低 32 代表了每代 Leader 中事務的唯一性。同時,也能讓 Follwer 通過高 32 位識別不同的 Leader。簡化了資料恢復流程。
2、基於這樣的策略:當 Follower 連結上 Leader 之後,Leader 伺服器會根據自己伺服器上最後被提交的 ZXID 和 Follower 上的 ZXID 進行比對,比對結果要麼回滾,要麼和 Leader 同步。
zookeeper叢集腦裂
叢集的腦裂通常是發生在節點之間通訊不可達的情況下,叢集會分裂成不同的小叢集,小叢集各自選出自己的master節點,導致原有的叢集出現多個master節點的情況。
zookeeper叢集節點數(奇數or偶數?)
只要我們清楚叢集leader選舉的要求(可用節點數量 > 總節點數量/2 。注意 是 > , 不是 ≥),我相信很容易明白奇數節點叢集相比偶數節點的叢集有更大的優勢。
1、發生腦裂(分成2個小叢集)的情況下,奇數節點的叢集總會有一個小叢集滿足可用節點數量 > 總節點數量/2,所以zookeeper叢集總能選取出leader。
2、在容錯能力相同的情況下,奇數叢集更節省資源。還是要清楚leader選舉的要求哈,舉個列子:3個節點的叢集,如果叢集可以正常工作(即leader選舉成功),至少需要2個節點是正常的;4個節點的叢集,如果叢集可以正常工作(即leader選舉成功),至少需要3個節點是正常的。那麼3個節點的叢集和4個節點的叢集都有一個節點當機的容錯能力。很明顯,在容錯能力相同的情況下,奇數節點的叢集更節省資源。
zookeeper和eureka對比
在分散式系統領域有個著名的 CAP定理(C- 資料一致性;A-服務可用性;P-服務對網路分割槽故障的容錯性,這三個特性在任何分散式系統中不能同時滿足,最多同時滿足兩個)。
zookeeper基於CP,即任何時刻對ZooKeeper的訪問請求能得到一致的資料結果,同時系統對網路分割具備容錯性;但是它不能保證每次服務請求的可用性(注:也就 是在極端環境下,zookeeper可能會丟棄一些請求,消費者程式需要重新請求才能獲得結果)。至於zookeeper為啥不能保證服務的高可用,大家可以想一下發生腦裂後無法選取leader、選取leader過程中丟棄某些請求。當網路出現故障時,剩餘zk叢集server會發起投票選舉新的leader,但是此過程會持續30~120s,此過程對於高併發來說十分漫長,會導致整個註冊服務的癱瘓,這是不可容忍的。
Eureka基於AP,不會有類似於ZooKeeper的選舉leader的過程,採用的是Peer to Peer 對等通訊,沒有leader/follower的說法,每個peer都是對等的;客戶端請求會自動切換 到新的Eureka節點;當當機的伺服器重新恢復後,Eureka會再次將其納入到伺服器叢集管理之中。當Eureka節點接受客戶端請求時,所有的操作都會在節點間進行復制(replicate To Peer)操作,將請求複製到該 Eureka Server 當前所知的其它所有節點中。至於為啥Eureka不能保證資料一致性,源於Eureka的自我保護機制:如果在15分鐘內超過85%的節點都沒有正常的心跳,那麼Eureka就認為客戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:
1. Eureka不再從註冊列表中移除因為長時間沒收到心跳而應該過期的服務 。
2. Eureka仍然能夠接受新服務的註冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用) 。
3. 當網路穩定時,當前例項新的註冊資訊會被同步到其它節點中。
因此, Eureka可以很好的應對因網路故障導致部分節點失去聯絡的情況,而不會像zookeeper那樣使整個註冊服務癱瘓。
總結
以上是對zookeeper的工作原理和相關概念的一些整理,希望能對大家認識zookeeper有所幫助。下一篇文章開始基於zookeeper做一個簡單的分散式配置中心,敬請期待!!!
參考連結
https://blog.csdn.net/pml18710973036/article/details/64121522
https://www.cnblogs.com/stateis0/p/9062133.html
https://www.jianshu.com/p/2bceacd60b8a