Zookeeper 高級
一致性協議概述
? 前面已經討論過,在分布式環境下,有很多不確定性因素,故障隨時都回發生,也講了 CAP理論,BASE 理論
? 我們希望達到,在分布式環境下能搭建一個高可用的,且資料高一致性的服務,目標是這樣, 但 CAP 理論告訴我們要達到這樣的理想環境是不可能的,這三者最多完全滿足 2 個,在這個前提下,P(磁區容錯性)是必然要滿足的,因為畢竟是分布式,不能把所有的應用全放到一個服務器里面,這樣服務器是吃不消的,而且也存在單點故障問題,所以,只能從一致性和可用性中找平衡,
? 怎么個平衡法?在這種環境下出現了 BASE 理論:
? 即使無法做到強一致性,但分布式系統可以根據自己的業務特點,采用適當的方式來使系統達到最終的一致性;
? BASE 由 Basically Avaliable 基本可用、Soft state 軟狀態、Eventually consistent 最終一致性組成,一句話概括就是:平時系統要求是基本可用,除開成功失敗,運行有可容忍的延遲狀態,但是,無論如何經過一段時間的延遲后系統最終必須達成資料是一致的,
? 其實可能發現不管是 CAP 理論,還是 BASE 理論,他們都是理論,這些理論是需要演算法來實作的,今天講的 2PC、3PC、Paxos 演算法,ZAB 演算法就是干這事情,
? 這些的前提一定是分布式,解決的問題全部都是在分布式環境下,怎么讓系 統盡可能的高可用,而且資料能最終能達到一致,
兩階段提交 two-phase commit (2PC)
? 首先來看下 2PC,翻譯過來叫兩階段提交演算法,它本身是一致強一致性演算法,所以很適合用作資料庫的分布式事務,其實資料庫的經常用到的 TCC 本身就是一種 2PC.
? 回想下資料庫的事務,資料庫不管是 MySQL 還是 MSSql,本身都提供的很完善的事務支持,MySQL 后面學分表分庫的時候會講到在 innodb 存盤引擎,對資料庫的修改都會寫到 undo和 redo 中,不只是資料庫,很多需要事務支持的都會用到這個思路,
? 對一條資料的修改操作首先寫 undo 日志,記錄的資料原來的樣子,接下來執行事務修改操作,把資料寫到 redo 日志里面,萬一捅婁子,事務失敗了,可從 undo 里面回復資料,
? 不只是資料庫,在很多企業里面,比如華為等提交資料庫修改都回要求這樣,你要新增一個 欄位,首先要把修改資料庫的欄位 SQL 提交給 DBA(redo),這不夠,還需要把洗掉你提交欄位,把資料還原成你修改之前的陳述句也一并提交者叫(undo)資料庫通過 undo 與 redo 能保證資料的強一致性,要解決分布式事務的前提就是當個節點是支持事務的,
? 這在個前提下,2pc 借鑒這失效,首先把整個分布式事務分兩節點,首先第一階段叫準備節點,事務的請求都發送給一個個的資源,這里的資源可以是資料庫,也可以是其他支持事務 的框架,他們會分別執行自己的事務,寫日志到 undo 與 redo,但是不提交事務,
? 當事務管理器收到了所以資源的反饋,事務都執行沒報錯后,事務管理器再發送 commit 指令讓資源把事務提交,一旦發現任何一個資源在準備階段沒有執行成功,事務管理器會發送rollback,讓所有的資源都回滾,這就是 2pc,非常非常簡單,

? 說他是強一致性的是他需要保證任何一個資源都成功,整個分布式事務才成功,
優點
? 優點:原理簡單,實作方便
缺點
? 缺點:同步阻塞,單點問題,資料不一致,容錯性不好
同步阻塞
? 在二階段提交的程序中,所有的節點都在等待其他節點的回應,無法進行其他操作,這種同 步阻塞極大的限制了分布式系統的性能,
單點問題
? 協調者在整個二階段提交程序中很重要,如果協調者在提交階段出現問題,那么整個流程將 無法運轉,更重要的是,其他參與者將會處于一直鎖定事務資源的狀態中,而無法繼續完成事務操作,
資料不一致
? 假設當協調者向所有的參與者發送 commit 請求之后,發生了區域網路例外,或者是協調者在尚未發送完所有 commit 請求之前自身發生了崩潰,導致最終只有部分參與者收到了
? commit 請求,這將導致嚴重的資料不一致問題,
容錯性不好
? 二階段提交協議沒有設計較為完善的容錯機制,任意一個節點是失敗都會導致整個事務的失敗,
三階段提交 three-phase commit (3PC)
? 由于二階段提交存在著諸如同步阻塞、單點問題,所以,研究者們在二階段提交的基礎上做 了改進,提出了三階段提交,

第一階段 canCommit
? 確認所有的資源是否都是健康、在線的,以約女孩舉例,你會打個電話問下她是不是在家, 而且可以約個會,
? 如果女孩有空,你在去約她,
? 就因為有了這一階段,大大的減少了 2 段提交的阻塞時間,在 2 段提交,如果有 3 個資料庫, 恰恰第三個資料庫出現問題,其他兩個都會執行耗費時間的事務操作,到第三個卻發現連接 不上,3 段優化了這種情況
第二階段 PreCommit
? 如果所有服務都 ok,可以接收事務請求,這一階段就可以執行事務了,這時候也是每個資源都回寫 redo 與 undo 日志,事務執行成功,回傳 ack(yes),否則回傳 no
第三階段 doCommit
? 這階段和前面說的 2 階段提交大同小異,這個時候協調者發現所有提交者事務提交者事務都正常執行后,給所有資源發送 commit 指令,
? 和二階段提交有所不同的是,他要求所有事務在協調者出現問題,沒給資源發送 commit 指令的時候,三階段提交演算法要求資源在一段時間超時后回默認提交做 commit 操作,
? 這樣的要求就減少了前面說的單點故障,萬一事務管理器出現問題,事務也回提交,
? 但回顧整個程序,不管是 2pc,還是 3pc,同步阻塞,單點故障,容錯機制不完善這些問題都沒本質上得到解決,尤其是前面說得資料一致性問題,反而更糟糕了,
? 所有資料庫的分布式事務一般都是二階段提交,而者三階段的思想更多的被借鑒擴散成其他 的演算法,
Paxos 演算法

? 這個演算法還是有點難度的,本身這演算法的提出者萊斯利·蘭伯特在前面幾篇論文中都不是以嚴謹的數學公式進行的,
? 其實這個 paxos 演算法也分成兩階段,首先這個圖有 2 個角色,提議者與接收者
第一階段
? 提議者對接收者吼了一嗓子,我有個事情要告訴你們,當然這里接受者不只一個,它也是個分布式集群
? 相當于星期一開早會,可恥的領導吼了句:“要開會了啊,我要公布一個編號為 001 的提案,收到請回復”,
? 這個時候領導就會等著,等員工回復 1“好的”,如果回復的數目超過一半,就會進行下一步,
? 如果由于某些原因(接收者死機,網路問題,本身業務問題),導通過的協議未超過一半,
? 這個時候的領導又會再吼一嗓子,當然氣勢沒那兇殘:“好了,怕了你們了,我要公布一個新的編號未 002 的提案,收到請回復 1”
第二階段
? 接下來到第二階段,領導苦口婆心的把你們叫來開會了,今天編號 002 提案的內容是:“由于專案緊張,今天加班到 12 點,同意的請舉手”這個時候如果絕大多少的接收者都同意, 那么好,議案就這么決定了,如果員工反對或者直接奪門而去,那么領導又只能從第一個階段開始:“大哥,大姐們,我有個新的提案 003,快回會議室吧,,”
詳細說明:
? 【注意:不懂沒事,記住上面那簡單情況就好】
? 上面那個故事描繪的是個苦逼的領導和兇神惡煞的員工之間的斗爭,通過這個故事你們起碼要懂 paxos 協議的流程是什么樣的(paxos 的核心就是少數服從多數),
? 上面的故事有兩個問題:
? 苦逼的領導(單點問題):有這一幫兇殘的下屬,這領導要不可能被氣死,要不也會辭職, 這是單點問題,
? 兇神惡煞的下屬(一致性問題):如果員工一種都拒絕,故意和領導抬桿,最終要產生一個一致性的解決方案是不可能的,
? 所以 paxos 協議肯定不會只有一個提議者,作為下屬的員工也不會那么強勢協議要求:如果接收者沒有收到過提案編號,他必須接受第一個提案編號如果接收者沒有收到過其他協議,他必須接受第一個協議,
? 舉一個例子:
? 有 2 個 Proposer(老板,老板之間是競爭關系)和 3 個 Acceptor(政府官員):
階段一
-
現在需要對一項議題來進行 paxos 程序,議題是“A 專案我要中標!”,這里的“我”指每個帶著他的秘書Proposer的Client老板,
-
Proposer 當然聽老板的話了,趕緊帶著議題和現金去找Acceptor政府官員,
-
作為政府官員,當然想誰給的錢多就把專案給誰,
-
Proposer-1小姐帶著現金同時找到了 Acceptor-1~Acceptor-3 官員,1 與 2 號官員分別收取了 10 位元幣,找到第 3 號官員時,沒想到遭到了 3 號官員的鄙視,3 號官員告訴她,Proposer-2給了 11 位元幣,不過沒關系,Proposer-1 已經得到了 1,2 兩個官員的認可,形成了多數派(如果沒有形成多數派,Proposer-1 會去銀行提款在來找官員們給每人 20 位元幣,這個程序一直重復每次+10 位元幣,直到多數派的形成),滿意的找老板復命去了,但是此時 Proposer-2 保鏢找到了 1,2 號官員,分別給了他們 11 位元幣,1,2 號官員的態度立刻轉變,都說Proposer-2的老板懂事,這下子 Proposer-2 放心了,搞定了 3 個官員,找老板復命去了,當然這個程序是第一階段提交,只是官員們初步接受賄賂而已,故事中的位元幣是編號,議題是 value,
這個程序保證了在某一時刻,某一個 proposer 的議題會形成一個多數派進行初步支持
階段二
-
現在進入第二階段提交,現在 proposer-1 小姐使用分身術(多執行緒并發)分了 3 個自己分別去找 3 位官員,最先找到了 1 號官員簽合同,遭到了 1 號官員的鄙視,1 號官員告訴他proposer-2 先生給了他 11 位元幣,因為上一條規則的性質 proposer-1 小姐知道 proposer-2 第一階段在她之后又形成了多數派(至少有 2 位官員的贓款被更新了);此時她趕緊去提款準備重新賄賂這 3 個官員(重新進入第一階段),每人 20 位元幣,剛給 1 號官員 20 位元幣, 1 號官員很高興初步接受了議題,還沒來得及見到 2,3 號官員的時候
? 這時 proposer-2 先生也使用分身術分別找 3 位官員(注意這里是 proposer-2 的第二階段),被第 1 號官員拒絕了告訴他收到了 20 位元幣,第 2,3 號官員順利簽了合同,這時 2,3 號官員記錄 client-2 老板用了 11 位元幣中標,因為形成了多數派,所以最終接受了 Client2 老板中標這個議題,對于 proposer-2 先生已經出色的完成了作業;
? 這時 proposer-1 小姐找到了 2 號官員,官員告訴她合同已經簽了,將合同給她看,proposer-1 小姐是一個沒有什么職業操守的聰明人,覺得跟 Client1 老板混沒什么前途,所以將自己的議題修改為“Client2 老板中標”,并且給了 2 號官員 20 位元幣,這樣形成了一個多數派,順利的再次進入第二階段,由于此時沒有人競爭了,順利的找 3 位官員簽合同,3 位官員看到議題與上次一次的合同是一致的,所以最終接受了,形成了多數派,proposer-1 小姐跳槽到 Client2 老板的公司去了,
總結:
? Paxos 程序結束了,這樣,一致性得到了保證,演算法運行到最后所有的 proposer 都投“client2 中標”所有的 acceptor 都接受這個議題,也就是說在最初的第二階段,議題是先入為主的,誰先占了先機,后面的 proposer 在第一階段就會學習到這個議題而修改自己本身的議題,因為這樣沒職業操守,才能讓一致性得到保證,這就是 paxos 演算法的一個程序,原來paxos 演算法里的角色都是這樣的不靠譜,不過沒關系,結果靠譜就可以了,該演算法就是為了追求結果的一致性,
Zookeeper 集群一致性協議 ZAB 決議
? 懂了 paxos 演算法,其實 zab 就很好理解了,很多論文和資料都證明 zab 其實就是 paxos 的一種簡化實作,但 Apache 自己的立場說 zab 不是 paxos 演算法的實作,這個不需要去計較,
? zab 協議解決的問題和 paxos 一樣,是解決分布式系統的資料一致性問題
? zookeeper 就是根據 zab 協議建立了主備模型完成集群的資料同步(保證資料的一致性), 前面介紹了集群的各種角色,這說所說的主備架構模型指的是,在 zookeeper 集群中,只有一臺 leader(主節點)負責處理外部客戶端的事務請求(寫操作),leader 節點負責將客戶端的寫操作資料同步到所有的 follower 節點中,

? zab 協議核心是在整個 zookeeper 集群中只有一個節點既 leader 將所有客戶端的寫操作轉化為事務(提議 proposal).leader 節點再資料寫完之后,將向所有的 follower 節點發送資料廣播請求(資料復制),等所有的 follower 節點的反饋,在 zab 協議中,只要超過半數 follower 節點反饋 ok,leader 節點會向所有 follower 服務器發送 commit 訊息,既將 leader 節點上的資料同步到 follower 節點之上,

? 發現,整個流程其實和 paxos 協議其實大同小異,說 zab 是 paxos 的一種實作方式其實并不過分,
? Zab 再細看可以分成兩部分,第一的訊息廣播模式,第二是崩潰恢復模式,

? 正常情況下當客戶端對 zk 有寫的資料請求時,leader 節點會把資料同步到 follower 節點,這個程序其實就是訊息的廣播模式
? 在新啟動的時候,或者 leader 節點奔潰的時候會要選舉新的 leader,選好新的 leader 之后會進行一次資料同步操作,整個程序就是奔潰恢復,
訊息廣播模式
? 為了保證磁區容錯性,zookeeper 是要讓每個節點副本必須是一致的
-
在 zookeeper 集群中資料副本的傳遞策略就是采用的廣播模式
-
Zab 協議中的 leader 等待 follower 的 ack 反饋,只要半數以上的 follower 成功反饋就好, 不需要收到全部的 follower 反饋,

zookeeper 中訊息廣播的具體步驟如下:
- 客戶端發起一個寫操作請求
- Leader 服務器將客戶端的 request 請求轉化為事物 proposql 提案,同時為每個 proposal 分配一個全域唯一的 ID,即 ZXID,
- leader 服務器與每個 follower 之間都有一個佇列,leader 將訊息發送到該佇列
- follower 機器從佇列中取出訊息處理完(寫入本地事物日志中)畢后,向 leader 服務器發送ACK 確認,
- leader 服務器收到半數以上的 follower 的 ACK 后,即認為可以發送 commit
- leader 向所有的 follower 服務器發送 commit 訊息,(在什么時候給client答復?)
? zookeeper 采用 ZAB 協議的核心就是只要有一臺服務器提交了 proposal,就要確保所有的服務器最終都能正確提交 proposal,這也是 CAP/BASE 最終實作一致性的一個體現,
? 回顧一下:前面還講了 2pc 協議,也就是兩階段提交,發現流程 2pc 和 zab 還是挺像的, zookeeper 中資料副本的同步方式與二階段提交相似但是卻又不同,二階段提交的要求協調者必須等到所有的參與者全部反饋 ACK 確認訊息后,再發送 commit 訊息,要求所有的參與者要么全部成功要么全部失敗,二階段提交會產生嚴重阻塞問題,但 paxos 和 zab 沒有這要求,
? 為了進一步防止阻塞,leader 服務器與每個 follower 之間都有一個單獨的佇列進行收發訊息,使用佇列訊息可以做到異步解耦,leader 和 follower 之間只要往佇列中發送了訊息即可,如果使用同步方式容易引起阻塞,性能上要下降很多
崩潰恢復

背景(什么情況下會崩潰恢復)
? zookeeper 集群中為保證任何所有行程能夠有序的順序執行,只能是 leader 服務器接受寫請求,即使是 follower 服務器接受到客戶端的請求,也會轉發到 leader 服務器進行處理,
? 如果 leader 服務器發生崩潰(重啟是一種特殊的奔潰,這時候也沒 leader),則 zab 協議要求zookeeper 集群進行崩潰恢復和 leader 服務器選舉,
最終目的(恢復成什么樣)
ZAB 協議崩潰恢復要求滿足如下 2 個要求:
確保已經被 leader 提交的 proposal 必須最終被所有的 follower 服務器提交,確保丟棄已經被 leader 提出的但是沒有被提交的 proposal,
? 新選舉出來的 leader 不能包含未提交的 proposal,即新選舉的 leader 必須都是已經提交了的proposal 的 follower 服務器節點,同時,新選舉的 leader 節點中含有最高的 ZXID,這樣做的好處就是可以避免了 leader 服務器檢查 proposal 的提交和丟棄作業,
- 每個 Server 會發出一個投票,第一次都是投自己,投票資訊:(myid,ZXID)
- 收集來自各個服務器的投票
- 處理投票并重新投票,處理邏輯:優先比較 ZXID,然后比較 myid
- 統計投票,只要超過半數的機器接收到同樣的投票資訊,就可以確定 leader
- 改變服務器狀態
問題:為什么優先選大的 zxid?
? 因為zkid最大,表明已提交的事務最大,資料最新,稱為leader可以將自己的資料賦值給follower,保證了資料一致性
zxid的編碼方式為高32位為epoch(即紀元,可以理解為代),低32位為每個proposal順序遞增的數字,每次變換一個leader,則epoch加一
初始化選舉

假設這些服務器從id1-5,依序啟動:
因為一共5臺服務器,只有超過半數以上,即最少啟動3臺服務器,集群才能正常作業,
- 服務器1啟動,發起一次選舉,
服務器1投自己一票,此時服務器1票數一票,不夠半數以上(3票),選舉無法完成;
服務器1狀態保持為LOOKING; - 服務器2啟動,再發起一次選舉,
服務器1和2分別投自己一票,此時服務器1發現服務器2的id比自己大,更改選票投給服務器2;
此時服務器1票數0票,服務器2票數2票,不夠半數以上(3票),選舉無法完成;
服務器1,2狀態保持LOOKING; - 服務器3啟動,發起一次選舉,
與上面程序一樣,服務器1和2先投自己一票,然后因為服務器3id最大,兩者更改選票投給為服務器3;
此次投票結果:服務器1為0票,服務器2為0票,服務器3為3票,此時服務器3的票數已經超過半數(3票),服務器3當選Leader,
服務器1,2更改狀態為FOLLOWING,服務器3更改狀態為LEADING; - 服務器4啟動,發起一次選舉,
此時服務器1,2,3已經不是LOOKING狀態,不會更改選票資訊,交換選票資訊結果:服務器3為3票,服務器4為1票,
此時服務器4服從多數,更改選票資訊為服務器3;
服務器4并更改狀態為FOLLOWING; - 服務器5啟動,同4一樣投票給3,此時服務器3一共5票,服務器5為0票;
服務器5并更改狀態為FOLLOWING;
崩潰恢復選舉
? 情況1: 現在假設leader3崩潰了,不同follower先后發起選舉的結果不一樣的,(假設zxid相同)
? 如果1發起選舉:
投票程序:
1投給1, 2投給2,4投給4,5投給5 (2,4,5都不會更改選票)
投票結果是沒有選出leader
? 如果2發起選舉結果同1
? 如果4發起選舉:
投票程序:
1投給1改選4, 2投給2改選4,4投給4,5投給5 (5不會更改選票)
投票選出leader4
? 此時已經選舉出leader, 各個節點狀態不是looking了,不在發起選舉
? 如果5先發起投票,結果就是5稱為leader
? 情況2: 現在假設leader3崩潰了,不同follower先后發起選舉的結果不一樣的,(假設節點1 zxid最大(實際已經提交的事務id中, 一定會有三臺都是最大的,方便描述,假設1,3最大))
? 無論哪一個發起投票,最終的leader總是節點1, 因為最終都會把自己的票改成zxid最大的那一個(除非一也掛了,但是更具zab協議,一定還會有一個機器的zxid也是和1,3相同的)
``
Zookeeper 集群決議
Zookeeper 集群特點

前面一種研究的單節點,現在來研究下 zk 集群,首先來看下 zk 集群的特點,
- 順序一致性
客戶端的更新順序與它們被發送的順序相一致, - 原子性
更新操作要么成功要么失敗,沒有第三種結果,(沒有第三狀態) - 單一視圖
無論客戶端連接到哪一個服務器,客戶端將看到相同的 ZooKeeper 視圖, - 可靠性
? 一旦一個更新操作被應用,那么在客戶端再次更新它之前,它的值將不會改變,
- 實時性
連接上一個服務端資料修改,所以其他的服務端都會實時的跟新,不算完全的實時,有一點延時的 - 角色輪換避免單點故障
當 leader 出現問題的時候,會選舉從 follower 中選舉一個新的 leader
集群中的角色
- Leader 集群作業機制中的核心
事務請求的唯一調度和處理者,保證集群事務處理的順序性集群內部個服務器的調度者(管理 follower,資料同步) - Follower 集群作業機制中的跟隨者
處理非事務請求,轉發事務請求給 Leader
參與事務請求 proposal 投票參與 leader 選舉投票 - Observer 觀察者
3.30 以上版本提供,和 follower 功能相同,但不參與任何形式投票,處理非事務請求,轉發事務請求給 Leader
提高集群非事務處理能力
Zookeeper 集群配置
不再贅述, 參考前文
【Zookeeper centos8 + zookeeper 3.7.0 環境安裝】_努力學習-CSDN博客
【Zookeeper windows 環境安裝】_努力學習-CSDN博客
Java 客戶端連接集群
ZKClient client = new ZKClient("host1:2181,host2:2181,host3:2181");
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/395201.html
標籤:區塊鏈
