Zookeeper 現在在分佈式架構中應用十分普遍,它做爲分佈式協調框架在分佈式架構中有着舉足輕重的地位,本文是主要從以上幾個方面對 Zookeeper 經常使用的知識進行總結。node
一 從集中式到分佈式架構的演變算法
架構的演變過程在以前的文章《淺談網站架構演變》中有所介紹數據庫
分佈式服務架構:服務器
分佈式架構:由多臺機器經過網絡通訊組成,分佈式的故障發生頻率大。
故障緣由:網絡問題,多臺機器網絡通訊容易超時,中間有可能斷掉形成分區。
網絡分區:俗稱腦裂。
網絡的三態問題:要麼鏈接成功,要麼失敗,要麼超時。網絡
因此分佈式主要是網絡方面和機器方面的問題,最大問題是網絡問題。session
傳統ACID 、 CAP理論、BASE理論:架構
傳統的集中式架構的事務討論的是 ACID :併發
原子性:要麼成功,要麼失敗;
一致性:若是出現異常數據,仍是原來的那份
隔離性:各個會話之間是相互獨立的
持久性:就是提交後的數據永久保存在磁盤上,不丟失。負載均衡
Consistency,Availability和Partition Tolerance,即CAP。框架
(C) 一致性:多臺機器擁有相同副本
(A) 可用性:在適合的時間響應客戶端
(P) 分區容錯性:不能出現網絡分區
CAP在分佈式架構中是不能都具有的,只能選擇兩種特性,而因爲分佈式架構都是集羣部署的,因此分區容錯性(P)是必需要的,可用性(A)、一致性(C)根據架構不一樣選擇的狀況也不一樣,Zookeeper 是CP 模型,也就是說 Zookeeper 在集羣出現問題時不會保證可用性,而是會犧牲部分對外服務時間,它保證的是數據的強一致性。
分佈式主要的問題是網絡問題,因此咱們優先處理分佈式的網絡問題,而後在一致性和可用性之間權衡。這時提出了 BASE 就是對 CAP 的一致性和可用性的權衡結果。
BASE 也叫基本可用,也就是最終一致性原則
最終一致性:就是你提交一臺機器,在必定時間內,數據會不一致,其餘機器最終會把你提交的那臺機器給同步到本身上,數據會最終一致。
二 分佈式事務、2PC、3PC 、Paxos
數據不一致問題:
在分佈式架構數據有多副本的狀況下,若是網絡、服務器或者軟件出現故障,會致使部分副本寫入成功,部分副本寫入失敗。這就形成各個副本之間的數據不一致,數據內容衝突,形成事實上的數據不一致。
2PC
兩階段提交協議是協調全部分佈式原子事務參與者,並決定提交或取消(回滾)的分佈式算法。
協議參與者
在兩階段提交協議中,系統通常包含兩類機器(或節點):一類爲協調者(coordinator),一般一個系統中只有一個;另外一類爲事務參與者(participants,cohorts 或 workers),通常包含多個,在數據存儲系統中能夠理解爲數據副本的個數。
協議中假設每一個節點都會記錄寫前日誌(write-ahead log)並持久性存儲,即便節點發生故障日誌也不會丟失。協議中同時假設節點不會發生永久性故障並且任意兩個節點均可以互相通訊。
兩個階段的執行
1.請求階段(commit-request phase,或稱表決階段,voting phase)
在請求階段,協調者將通知事務參與者準備提交或取消事務,而後進入表決過程。
在表決過程當中,參與者將告知協調者本身的決策:贊成(事務參與者本地做業執行成功)或取消(本地做業執行故障)。
2.提交階段(commit phase)
在該階段,協調者將基於第一個階段的投票結果進行決策:提交或取消。
當且僅當全部的參與者贊成提交事務協調者才通知全部的參與者提交事務,不然協調者將通知全部的參與者取消事務。
參與者在接收到協調者發來的消息後將執行響應的操做。
兩階段提交的缺點
1. 同步阻塞問題
執行過程當中,全部參與節點都是事務阻塞型的。當參與者佔有公共資源時,其餘第三方節點訪問公共資源不得不處於阻塞狀態。
2.單點故障
因爲協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤爲在第二階段,協調者發生故障,那麼全部的參與者還都處於鎖定事務資源的狀態中,而沒法繼續完成事務操做。(若是是協調者掛掉,能夠從新選舉一個協調者,可是沒法解決由於協調者宕機致使的參與者處於阻塞狀態的問題)
3.數據不一致
在二階段提交的階段二中,當協調者向參與者發送 commit 請求以後,發生了局部網絡異常或者在發送 commit 請求過程當中協調者發生了故障,這回致使只有一部分參與者接受到了 commit 請求。
而在這部分參與者接到 commit 請求以後就會執行 commit 操做。可是其餘部分未接到 commit 請求的機器則沒法執行事務提交。因而整個分佈式系統便出現了數據部一致性的現象。
兩階段提交沒法解決的問題
當協調者出錯,同時參與者也出錯時,兩階段沒法保證事務執行的完整性。
考慮協調者在發出 commit 消息以後宕機,而惟一接收到這條消息的參與者同時也宕機了。那麼即便協調者經過選舉協議產生了新的協調者,這條參與者事務的狀態也是不肯定的,沒人知道事務是否被已經提交。
3PC
三階段提交協議在協調者和參與者中都引入超時機制,而且把兩階段提交協議的第一個階段拆分紅了兩步:詢問,而後再鎖資源,最後真正提交。
三個階段的執行
CanCommit 階段
3PC 的 CanCommit 階段其實和 2PC 的準備階段很像。
協調者向參與者發送 commit 請求,參與者若是能夠提交就返回 Yes 響應,不然返回 No 響應。
PreCommit 階段
協調者根據參與者的反應狀況來決定是否能夠繼續事務的 PreCommit 操做。
根據響應狀況,有如下兩種可能:
假如協調者從全部的參與者得到的反饋都是 Yes 響應,那麼就會進行事務的預執行:
發送預提交請求。協調者向參與者發送 PreCommit 請求,並進入Prepared 階段。
事務預提交。參與者接收到 PreCommit 請求後,會執行事務操做,並將 undo 和 redo 信息記錄到事務日誌中。
響應反饋。若是參與者成功的執行了事務操做,則返回 ACK 響應,同時開始等待最終指令。
2.假若有任何一個參與者向協調者發送了 No 響應,或者等待超時之 後,協調者都沒有接到參與者的響應,那麼就中斷事務:
發送中斷請求。協調者向全部參與者發送中斷請求。
中斷事務。參與者收到來自協調者的中斷請求以後(或超時以後,仍未收到中斷的請求),執行事務的中斷。
DoCommit 階段
該階段進行真正的事務提交,也能夠分爲如下兩種狀況:
執行提交
發送提交請求。協調者接收到參與者發送的 ACK 響應,那麼他將從預提交狀態進入到提交狀態。並向全部參與者發送 doCommit 請求。
事務提交。參與者接收到 doCommit 請求以後,執行正式的事務提交。並在完成事務提交以後釋放全部事務資源。
響應反饋。事務提交完以後,曏者發送 ACK 響應。
完成事務。協調者接收到全部參與者的 ACK 響應以後,完成事務。
中斷事務
協調者沒有接收到參與者發送的ACK響應(多是接受者發送的不是 ACK 響應,也可能響應超時),那麼就會執行中斷事務。
三階段提交協議和兩階段提交協議的不一樣
對於協調者(Coordinator)和參與者(Cohort)都設置了超時機制(在 2PC 中,只有協調者擁有超時機制,即若是在必定時間內沒有收到參與者的消息則默認失敗)。
在 2PC 的準備階段和提交階段之間,插入預提交階段,使 3PC 擁有CanCommit、PreCommit、DoCommit 三個階段。
PreCommit 是一個緩衝,保證了在最後提交階段以前各參與節點的狀態是一致的。
三階段提交協議的缺點
若是進入 PreCommit 後,協調者發出的是中斷請求,假設只有一個參與者收到並進行了中斷操做;
而其餘對於系統狀態未知的參與者會根據 3PC 選擇繼續 Commit,此時系統狀態發生不一致性。
有個叫 paxos小島,島上居民每項決定都得經過提議而後半數才能生效,每一個決定的提議都有一個惟一的全局編號,這個編號只能自增加,不能後退。
何爲經過:就是提議的 id 號要大於議員手記錄的最大的 id
第一階段:提議者發起提議給每一個議員,而後等議員反饋贊成或不一樣意。
第二階段:若是半數以上贊成了,則執行事務,不然不執行。
若是半數以上贊成了,這個議題就經過,而後提議者就命令剩下的議員同步本身的數據,並修改手上的最大 id 號。
問題:
在分佈式中併發是常見的,例如如今有提議者 p1,p2
提議者同時提出一個提議,這個時候他們手上的 id 就有多是同樣,p1的 id 是3,p2的 id 也是3。當 p1 提議給議員(假設議員手上的 id是 2),如今議員先贊成了 p1,p2 來訪問這個議員,議員告訴他已經贊成了議題 id 是 3,p2 的 id 是 3 不一樣意。而後p2回去加大本身的 id從新請求,議員這時贊成了他。p1 收到半數贊成準備去通知他們來更新 id 同步數據,但是發現議員們的 id 比本身的大了,而後 p1 又加大 id。這種極端狀況,致使死鎖了。
這種解決辦法就是提議者只有一個,也就是 paxos 裏面說的總統。
三 Zookeeper 簡介
Zookeeper 是爲了解決分佈式一致性問題的工程應用。
Zookeeper 並無直接用 paxos 協議,而是在 paxos 協議的基礎上,提出了符合本身符合實際應用場景的高可用的一致性協議 --- ZAB 原子廣播協議。
Zookeeper 分佈式一致性的特色:
順序一致性:客戶端訪問 Zookeeper 的一個節點,發起事務,是排着隊到 leader 那讓他發起提議,一個一個來;
單一視圖:任何節點上的數據都是同樣的,因此客戶端訪問任意節點都看到是相同的數據。
可靠性:給了一個客戶端反饋,贊成他的請求,那麼就是真的贊成了。
實時性:Zookeeper 保證在必定時間內,好比 5 秒以後你能夠訪問到最新數據。這是最終一致性致使的。
簡單的數據模型:就是文件夾的樹形結構
能夠構建集羣:
順序訪問:客戶端提出了一個事務請求,會得到一個惟一的id編號,用於操做的前後順序;
高性能:這裏指的是讀取數據
Zookeeper有幾個角色:leader、follower、observer;其中observer 通常不配置,它也不參與投票,observer 能夠在不影響寫性能的狀況下提高集羣的讀性能;
Zookeeper 中節點有實體機器節點,還有 znode 數據節點。znode 數據節點指的是目錄文件夾。數據節點有永久數據節點和臨時節點。
Zookeeper 有 watcher 監聽機制,例如一個臨時數據節點,若是客戶session 中斷了,臨時節點就刪除了,這時 watche r就監聽到了。這點就是 hadoop 的 HA 實現機制,zkfc 實現了 Zookeeper 的 watcher機制來自動切換。
Zookeeper 的數據節點就是一個文件夾目錄,它有本身的權限機制ACL 。 ACL是Access Control Lists 的簡寫, ZooKeeper 採用 ACL 策略來進行權限控制,有如下權限:
CREATE:建立子節點的權限
READ:獲取節點數據和子節點列表的權限
WRITE:更新節點數據的權限
DELETE:刪除子節點的權限
ADMIN:設置節點 ACL 的權限
實際 Zookeeper 刪除、設置、建立目錄,這些就是執行權限。
四 ZAB 原子廣播協議
Looking/election : 系統剛啓動時或者 Leader 崩潰後正處於選舉狀態;
Following:Follower 節點所處的狀態,Follower 與 Leader 處於數據同步階段;
Leading:Leader 所處狀態,當前集羣中有一個 Leader 爲主進程。
宏觀上來看分爲:
崩潰恢復階段
快速選舉階段
原子廣播階段
微觀上來看分爲:
leader 選舉階段
節點在選舉開始讀默認投票給本身,當接收其餘節點的選票時,會 根據上面的條件更改本身的選票並從新發送選票給其餘節點,當一 個節點的獲得票超過半數,該節點會設置本身的狀態 leading,其 他節點會設置本身的狀態爲 following。
成爲 leader 的條件:
選 epoch 最大的;
epoch 相等,選 zxid 最大的
epoch和 zxid 都相等,選擇 server id最大的(就是配置 zoo.cfg 中的 myid)。
那什麼是 epoch,什麼是 zxid 呢?
epoch 是 leader 標識,zxid 是事務標識。
epoch 是指:年代,一個領導掛了,另外一個領導上任,如今就是新領導的時代了,當產生新領導,事務編號就從0開始。
zxid是總稱:前32位是 leader 編號(epoch),後32位是這個 leader下事務編號。
首先 ZooKeeper 一個事務包含兩部分,一個是數據,一個是id;
id是全局惟一的 id,數據就是具體操做數據,而且是 lastid 加1,
ZooKeeper 每一個請求都是順序執行的,強順序性的。
發現階段
發現階段主要是發現最大的 epoch 和最大的事務編號;
第一階段快速產生準備 leader,其餘節點就是 follower,而後在發現階段 follower 向 leader報告本身的epoch和事務編號,leader 進行排序,選擇最大的 epoch 和最大的事務編號,以後通知 follower 去更改它的 epoch。
同步階段
leader 利用上一個階段知道最大事務編號,而後通知其餘 follower 去leader 這同步數據。事務編號有可能不同,因此要同步。保持數據最終一致性。
原子廣播階段
這時候 leader 真正對外提供服務,接受客戶端的請求,生成一個數據,半數以上贊成,而後就提交事務。剩下的其餘節點直接去 leader 那同步數據。
掛掉的 leader 啓動起來,發現它的時代已通過時了,就刪除事務,發現有新的 leader,本身就變成 follower,而後就去同步數據。
在選舉上,會選舉擁有最新提議歷史( lastzxid最大)的節點做爲leader,這樣子就省去了發現最新提議的步驟。這是局域擁有最新提議的節點也有最新提交記錄的前提。
ZAB 協議並非 Paxos 算法的一個典型實現,在講解 ZAB 和 Paxos 之間的區別以前,咱們首先來看下二者的聯繫。
二者都存在一個相似於Leader進程的角色,由其負責協調多個 Follow 進程的運行。
Leader 進程都會等待超過半數的 Follower 作出正確的反饋後,纔會將一個提案進行提交。
在ZAB協議中,每一個提議中都包含了一個 epoch 值,用來表明當前Leader 週期,在 Paxos 算法中,一樣存在這樣一個標識,只是名字變成了 Ballot。
在 Paxos 算法中,一個新選舉產生的主進程會進行讀和寫兩個階段的工做。
第一階段被稱爲讀階段,在這個階段中,這個新的主進程會經過和全部其餘進程進行通訊的方式來收集上一個主進程的提案,並將他們提交。
第二階段被稱爲寫階段,在這個階段,當前主進程開始提出他本身的提案。
在Paxos算法設計的基礎上,ZAB 協議額外添加了一個同步階段,ZAB 會進行 發現階段(相似 paxos 讀階段)、同步階段、寫階段(相似 paxos 寫階段)。
在同步階段以前,ZAB 協議也存在一個和 Paxos 算法中的讀階段很是相似的過程,稱爲發現(Discovery)階段。
在同步階段中,新的 Leader 會確保存在過半的 Follower 已經提交了以前 Leader 週期中的全部事務 提議 。
這一同步階段的引入,可以有效地保證 Leader 在新的週期中提出事務提議以前,全部的進程都已經完成了對以前全部事務提議的提交。
一旦完成同步階段後,那麼 ZAB 就會執行和 Paxos 算法相似的寫階段。
總的來說,ZAB 協議和 Paxos 算法的本質區別在於,二者的設計目標不太同樣。
ZAB 協議主要用於構建一個高可用的分佈式數據主備系統,例如ZooKeeper,而 Paxos 算法則是用於構建一個分佈式的一致性狀態機系統。
五 Zookeeper 應用
ZooKeeper 目錄有幾個特色,有臨時目錄,永久目錄,順序目錄,強一致性(順序訪問)和 watcher 機制。
利用這些特色,咱們能夠實現:
發佈訂閱,例如一些配置信息;
負載均衡,例如kafka生產,消費均衡;
master選舉,例如 hbase 利用它 hmaster 選舉;
主備切換,例如 hdfs 的 HA 利用它進行切換。
例如:咱們的數據庫配置信息文件就能夠放到 ZooKeeper 上。
利用 ZooKeeper 的 watcher 機制實現配置變動,程序在運行中就能夠獲取到最新的配置信息,不須要起停。
hdfs 的 HA,它的主備切換用的是 ZooKeeper 來作 Active standby 之間切換的。
大體步驟:
多個 nodemanager 同時向 ZooKeeper 註冊一個數據節點 lock 。由於 ZooKeeper 是強一致性的,因此只能有一個註冊成功,註冊成功的那個就是 active
沒有註冊成功的否成了 standby,而後在 lock 目錄上註冊監聽事件 watcher。
注意:註冊的 lock 節點目錄是臨時節點,若是 active 掛了,這個目錄也就沒了,而且這個 lock 目錄是有權限控制的 ACL,防止 active 假死後從新鏈接出現腦裂。
主備切換:當 active 掛掉之後,會話結束,臨時目錄自動刪除。其餘 standby 監聽到臨時目錄刪除了,各個 standby 從新同時進行建立帶權限的臨時目錄。成功的改成 active,沒有成功的仍是standby
若是掛掉的 active 啓動後,發現沒有權限範圍lock臨時目錄,自動更改爲 standby 狀態。
這是 ZooKeeper 主備切換應用,利用臨時目錄,ACL,watcher機制實現。
利用 Zookeeper master 選舉其實很簡單,和主備切換同樣。
利用強一致性同時建立同一個目錄,最後只能一個成功,成功那個節點會返回成功狀態,其餘節點返回異常,成功的那個就成爲 master,其餘節點就改爲 slave 。
hmaster 監控 regionserver 是否掛掉。
首先,rs(regionserver簡稱)在ZooKeeper註冊一個臨時目錄rs/[hostname] 目錄,而後 hmaster 註冊 watcher 監控 rs 目錄下面變化就能夠發現 rs 服務器是否掛掉。
元數據存儲(訂閱發佈):每一個 region 存儲信息位置和狀態,都放在 ZooKeeper 上存儲,以便你們都能訂閱目前 region 所處的狀態,好比 region 是在合併仍是在切割,有多少個 region 分別在哪一個regionserver 上。
因此客戶端訪問先訪問 Zookeeper 獲得位置信息去讀取數據,不通過hmaster。
kafka 在 Zookeeper 註冊的信息
首先,kafka 會把 broker 建立到 Zookeeper 臨時目錄上。
/broker/ids/[1-n] 表示 broker 還活着。而後 topic 信息建立到 Zookeeper 臨時目錄/brokers/topics/[topicname]/paritiong 信息。若是有消費者,消費者也會在 Zookeeper 建立本身消費信息的offset信息等臨時目錄。
kafka 註冊 broker 和 topic 信息使爲了生產消費時負載均衡,這就利用到 Zookeeper 負載均衡。消費生產者監控到 broker 和 topic ,topic 和 partition 之間的數量,進行從新排序。
參考書籍:
《從Paxos到Zookeeper 分佈式一致性原理與實踐》
少俠,我看你骨骼精奇,關注一下,我這本武林祕籍就是你的了~