什麼是paxos演算法
是一種基於訊息傳遞的,具有高容錯的一致性演算法。
解決了什麼問題
主要解決分散式系統中,如何就某個決策達成一致性的問題。主要的工程實現,ZAB,Google Chubby、微信的 PhxPaxos。
paxos演算法與拜占庭將軍問題
paxos演算法的作者認為,在通道不可信的前提下,通過訊息傳遞的方式達成一致性,是不可能的。因此,paxos演算法的前提是不存在拜占庭將軍問題。也就是,認為通道是可信的,叢集間傳遞的訊息,不會被篡改。分散式系統中,各個節點訊息的傳遞方式有兩種,共享記憶體和訊息傳遞。paxos是基於訊息傳遞通訊模型。
paxos的三種角色
在paxos演算法中有三種角色,每種角色有不同的功能。但很多時候,一個程式可能充當多種角色。Proposal,提案;
- Proposer:提案者
- Accecptor:決策者
- Learner:學習者,同步者
##paxos演算法的一致性 paxos演算法的一致性,通過以下幾點去保證:
- 每個提案者在提案的時候,首先需要獲取一個全域性唯一,遞增的編號N,將N賦給提案。N的生成方式有兩種,全域性性生成器、提案者自身維護。
- 每個表決者在接收到提案之後,會把提案編號儲存在本地。這樣每個表決者都有一個最大編號,假設是maxN。而每個表決者只會accept編號大於自己本地maxN的提案。
- 最終只有一個提案被選定
- 一旦一個提案被選定,那麼learner會同步該提案到本地。
- 當然,沒有提案選出就不會有提案被選定
提交提案的兩種演算法
2PC和3PC演算法:
- 2PC演算法:Tow Phase Commit 即,prepare->accept
- 3PC演算法:Three Phase Commit 即,prepare->accept->commit
區別就是accept階段是否有commit功能。
3PC演算法描述
3PC演算法一共有三個階段,準備,接收,提交。
prepare準備階段:
- 提案者準備一個編號N的提議,然後向決策者傳送prepare(N),用於試探叢集是否支援該提案。
- 每個決策者本地都有一個maxN,當接收到prepare(N)的時候,會與自己的maxN進行比較,有幾種情況。
- 若N小於maxN,說明該提案已經過時,那麼就不回應或者回應error,來拒絕該提案。
- 若N大於maxN,說明決策者可以接收該提案,會返回一個Proposal(myid,maxN,value),曾經接收的最大maxN的提案,來表示自己願意接收該提案。myid就是該提案者的id,maxN就是該提案的編號,value就是提案的值。如果是第一次接收,就都是null。
accept接收階段
- 若提案者,接收到超過半數的反饋之後,那麼提案者就會把真正的提案Proposal(myid,N,value),傳送給所有的決策者。
- 當決策者接收到提案之後,會再次與本地的maxN或者prepare記錄下的N,進行比較,若N大於等於該編號,那麼決策者就會accept該提案,並返回給提案者。否則,就會拒絕該提案
- 若提案者沒有接收到超過半數決策的反饋的accept。那麼,要麼放棄提案,要麼遞增編號,重新提交請求,從prepare開始。
commit提交階段
若提案者接收到超過半數的反饋,就會向外傳送廣播資訊
- 向accept的決策者傳送“可執行資料同步資訊”,讓決策者執行曾經接收到的提案。
- 向未反饋的決策者,傳送“提案+可執行資訊”,讓他們接收到後馬上執行。
2PC演算法過程
2PC就是沒有提交過程,就是在prepare成功之後,會把真正的提交直接傳送給決策者,決策者接收到提案後會直接執行資料同步。不用等到commit訊息。2PC是有較多的弊端的,但是效率較高。
paxos演算法的活鎖問題
活鎖:活鎖就是一直重複嘗試-失敗-嘗試-失敗的過程,但是活鎖有可能自己解開。就是如果有很多提案一直提交,有可能某個提案一直失敗,一直遞增N,一直重試還是失敗,但是有可能某次就成功了。
#ZAB協議 ZAB:zookeeper Atomic Broadcast,zk原子性廣播協議。專門為zk設計的支援崩潰恢復的廣播協議,用來實現分散式系統中資料一致性。ZAB使用一個單一程式來處理所有的寫請求。當伺服器資料狀態放生變更了之後,叢集才用ZAB廣播協議,以事務提案Proposal的方式廣播給所有的副本。ZAB協議能夠保證一個全域性唯一遞增的xid。zk客戶端傳送讀請求的時候,如果接受者不是leader,那麼就會把請求轉發給leader,只有master能夠處理寫請求。
paxos和ZAB
ZAB是paxos的工業實現,目的是構建一個高可用的分散式資料主從系統,follower是leader的從機,leader掛了可以馬上從follower選一個leader。ZAB為了解決活鎖問題,只允許一個程式提交提案,屬於3PC提交。而,leader掛了時候選舉演算法是2PC,所有的follower都可以提交,就是我選我。
三種角色
- leader:zk中寫請求的唯一處理者,也能處理讀請求。
- follower:處理讀請求、對leader的提案進行表決、同步leader的結果、具有選舉權和被選舉權
- observer:沒有表決權。只能處理寫請求、沒有選舉和被選舉權。 learner=follower+observer
三個資料
- zxid:64位長度,高位32位是epoch,低32為xid
- epoch:每個leader都有一個新的epoch,可以認為是年代?
- xid:流水號。
三種模式
zk中有三種模式,沒有明顯的分界線,都交織在一起
- 恢復模式:包含兩個重要階段,leader選舉和初始化同步
- 廣播模式:包含兩類,初始化廣播和更新廣播
- 同步模式:包含兩類,初始化同步和更新同步
同步模式
初始化同步:恢復模式中有兩個階段,leader選舉和初始化同步,當leader選出來之後只是一個準leader,只有經過初始化同步之後,才是一個真正的leader。 同步過程:
- Leader為保證向每一個learner傳送的有序性,會為每一個learner準備一個對列。
- Leader將那些沒有被learner同步到的事務封裝成proposal放入佇列。
- Leader將proposal傳送給learner並加上commit訊息,表示事務已經提交,可以直接執行。
- learner接收到訊息後,同步到本地
- 向leader傳送ack訊息
- Leader接收到ack訊息之後,會把learner加入到可用的follower列表會在observer列表。如果沒有返回ack或者ack沒有被leader收到,就不會加入到可用列表中。
訊息廣播演算法: 當leader完成同步之後,就進入正常的工作狀態,如果有寫請求,過來那麼leader會執行以下過程。
- leader接收到事務後,會為該事務生成一個全域性唯一的id,zxid,並且將事務封裝更一個Proposal。
- Leader獲取到所有的follower列表,並通過每個follower的佇列,把proposal傳送給follower
- follower接收到proposal之後會與自己本地已經儲存的最大zxid進行比較,如果當前的zxid較大,則把proposal儲存到本地日誌事務中,並返回ack
- 當leader收到超過半數的ack之後,就會向所有的follower傳送commit訊息,把proposal傳送給observer。
- 當follower接收到commit訊息之後,會把事務正式更新到本地。而observer接收到proposal會直接更新到本地。
- follower和observer更新完訊息之後,就會向leader反饋ack。
四種狀態
每臺主機,在不同的節點會有不同的狀態
- LOOKING:選舉狀態
- FOLLOWER:follower正常的工作狀態
- OBSERVERING:observer正常的工作狀態
- LEADING:leader正常的工作狀態
observer數量問題
observer數量並不需要太多,雖然observer能夠在一定程度上提高系統的吞吐量,但是需要從leader同步資料。而Observer的同步時間是小於follower的同步時間的,當follower同步完成observer同步也就結束了,同步完成的observer會被加入到可用列表,而沒有同步完成的observer無法提高服務,就會造成資源浪費。
恢復模式的三個原則:
- 主動讓出原則:若leader收到follower心跳的數量沒有過半,那麼leader會任務自己與叢集連線出現問題,會自動把自己的狀態改成LOOKING,重新去查詢leader。而去他的follower發現超過半數的主機任務失去leader,會重新進行選舉
- 已處理的訊息不能丟:如果有的follower還沒收到commit訊息的時候leader掛了,那麼就會導致該事務有的server執行了有的沒有。當新的leader被選出,經過恢復模式後,就需要保證叢集中所有server執行了之前部分server執行的事務。
- 被丟的訊息不能再現:當一個事務被通過,leader已經更新到本地了,但是還沒向follower傳送commit之前掛了。這臺機器再次成為follower的時候,本地上就會比其他機器多一個事務,是不行的。因此,類似這樣的事務是應該被丟棄的。而這種情況,服務端也不會向客戶端返回成功的訊息。