介紹常見的分佈式一致性協議html
CAP理論又稱之爲布魯爾定理(Brewer’S theorem),認爲在設計一個大規模可擴放的網絡服務時候不能同時兼容:一致性(consistency)、可用性(Availability)、分區容錯(Partition-tolerance)。git
一致性:在分佈式系統中的全部數據備份,在同一時刻是否有一樣的值。(等同於全部節點訪問同一份最新的數據副本)github
可用性:在集羣中一部分節點故障後,集羣總體是否還能響應客戶端的讀寫請求。算法
分區容忍性:以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇數據庫
CAP理論容易理解,網上也有關於該理論的說明,包括模型的簡易證實;弱條件下模型的成立等。apache
參考資料:安全
http://www.cnblogs.com/mmjx/archive/2011/12/19/2290540.html服務器
http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html網絡
BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的簡寫,BASE是對CAP中一致性和可用性權衡的結果,其來源於對大規模互聯網系統分佈式實踐的結論,是基於CAP定理逐步演化而來的,其核心思想是即便沒法作到強一致性(Strong consistency),但每一個應用均可以根據自身的業務特色,採用適當的方式來使系統達到最終一致性(Eventual consistency)架構
基本可用:分佈式系統在出現故障的時候,容許損失部分可用性,即保證核心可用。
軟狀態:容許系統存在中間狀態,而該中間狀態不會影響系統總體可用性
最終一致性:系統中的全部數據副本通過必定時間後,最終可以達到一致的狀態
兩階段提交(Two-phaseCommit)是指,在計算機網絡以及數據庫領域內,爲了使基於分佈式系統架構下的全部節點在進行事務提交時保持一致性而設計的一種算法。
在分佈式系統中,每一個節點雖然能夠知曉本身的操做時成功或者失敗,卻沒法知道其餘節點的操做的成功或失敗。當一個事務跨越多個節點時,爲了保持事務的ACID特性,須要引入一個做爲協調者的組件來統一掌控全部節點(稱做參與者)的操做結果並最終指示這些節點是否要把操做結果進行真正的提交。
如上圖示,該協議分爲兩個階段:
請求階段(commit-request phase,或稱表決階段,voting phase)
在請求階段,協調者將通知事務參與者準備提交或取消事務,而後進入表決過程。在表決過程當中,參與者將告知協調者本身的決策:贊成(事務參與者本地做業執行成功)或取消(本地做業執行故障)。
提交階段(commit phase)
在該階段,協調者將基於第一個階段的投票結果進行決策:提交或取消。當且僅當全部的參與者贊成提交事務協調者才通知全部的參與者提交事務,不然協調者將通知全部的參與者取消事務。參與者在接收到協調者發來的消息後將執行相應的操做。
二階段提交算法的最大缺點就在於它在執行過程當中間,節點都處於阻塞態。即節點之間在等待對方的響應消息時,它將什麼也作不了。特別是,當一個節點在已經佔有了某項資源的狀況下,爲了等待其餘節點的響應消息而陷入阻塞狀態時,當第三個節點嘗試訪問該節點佔有的資源時,這個節點也將連帶陷入阻塞狀態。
另外,協調者節點指示參與者節點進行提交等操做時,若有參與者節點出現了崩潰等狀況而致使協調者始終沒法獲取全部參與者的響應信息,這時協調者將只能依賴協調者自身的超時機制來生效。但每每超時機制生效時,協調者都會指示參與者進行回滾操做。這樣的策略顯得比較保守。
參考資料
與兩階段提交不一樣的是,三階段提交是「非阻塞」協議。三階段提交在兩階段提交的第一階段與第二階段之間插入了一個準備階段,同時對於協調者和參與者都設置了超時機制,使得原先在兩階段提交中,參與者在投票以後,因爲協調者發生崩潰或錯誤,而致使參與者處於沒法知曉是否提交或者停止的「不肯定狀態」所產生的可能至關長的延時的問題得以解決。
如上圖示,該協議分爲三個階段:
協調者向參與者發送commit請求,參與者若是能夠提交就返回Yes響應,不然返回No響應。
preCommit
協調者根據參與者的反應狀況來決定是否能夠進行事務的PreCommit操做。根據響應狀況,有如下兩種可能.
發送預提交請求,Coordinator向Cohort發送PreCommit請求,並進入Prepared階段。
事務預提交,Cohort接收到PreCommit請求後,會執行事務操做,並將undo和redo信息記錄到事務日誌中。
響應反饋,若是Cohort成功的執行了事務操做,則返回ACK響應,同時開始等待最終指令。
發送中斷請求,Coordinator向全部Cohort發送abort請求。
中斷事務,Cohort收到來自Coordinator的abort請求以後(或超時以後,仍未收到Cohort的請求),執行事務的中斷。
doCommit
該階段進行真正的事務提交,也能夠分爲如下兩種狀況:
A.發送提交請求。Coordinator接收到Cohort發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向全部Cohort發送doCommit請求。
B.事務提交。Cohort接收到doCommit請求以後,執行正式的事務提交。並在完成事務提交以後釋放全部事務資源。
C.響應反饋。事務提交完以後,向Coordinator發送ACK響應。
D.完成事務。Coordinator接收到全部Cohort的ACK響應以後,完成事務。
參考資料:
在常見的分佈式系統中,總會發生諸如機器宕機或網絡異常等狀況。Paxos算法須要解決的問題就是如何在一個可能發生上述異常的分佈式系統中,快速且正確地在集羣內部對某個數據的值達成一致,而且保證不論發生以上任何異常,都不會破壞整個系統的一致性。這裏某個數據的值並不僅是狹義上的某個數,它能夠是一條日誌,也能夠是一條命令(command)等,根據應用場景不一樣,某個數據的值有不一樣的含義。
在Paxos算法中,有三種角色:
Proposer:提案發起者,向集羣中的其餘節點發一個提案Proposal,該提案中有一個對應的值。
Acceptor:提案接受者,負責處理接收到的提議,他們的回覆就是一次投票。會存儲一些狀態來決定是否接收一個值。
Learners:不參與提案的發起和投票,學習已經被Acceptor接受的提案
保證最終有一個value會被選定,當value被選定後,進程最終也能獲取到被選定的value。
安全性原則:保證不能作錯的事。只能有一個值被批准,不能出現第二個值把第一個覆蓋的狀況;每一個節點只能學習到已經被批准的值,不能學習沒有被批准的值。
存活原則:只要有多數服務器存活而且彼此間能夠通訊最終都要作到的事。最終會批准某個被提議的值;一個值被批准了,其餘服務器最終會學習到這個值。
Basic Paxos算法分爲兩個階段。具體以下:
Proposer選擇一個提案編號N,而後向半數以上的Acceptor發送編號爲N的Prepare請求。
若是一個Acceptor收到一個編號爲N的Prepare請求,且N大於該Acceptor已經響應過的全部Prepare請求的編號,那麼它就會將它已經接受過的編號最大的提案(若是有的話)做爲響應反饋給Proposer,同時該Acceptor承諾再也不接受任何編號小於N的提案。
若是Proposer收到半數以上Acceptor對其發出的編號爲N的Prepare請求的響應,那麼它就會發送一個針對[N,V]提案的Accept請求給半數以上的Acceptor。注意:V就是收到的響應中編號最大的提案的value,若是響應中不包含任何提案,那麼V就由Proposer本身決定。
若是Acceptor收到一個針對編號爲N的提案的Accept請求,只要該Acceptor沒有對編號大於N的Prepare請求作出過響應,它就接受該提案。
示例過程以下,其中MaxN,AccerptN,AcceptV分別表示Acceptor的最大響應提案編號,接受的最大編號和接受編號對應的值:
1)只有一個Acceptor,只要Acceptor接受它收到的第一個提案並被選定,則能夠保證只有一個value會被選定。 2)多個Acceptor 提案(Propersal) = [value] 即便只有一個Proposer提出了一個value,該value也最終被選定 => P1:一個Acceptor必須接受它收到的第一個提案。 => 若是每一個Proposer分別提出不一樣的value,發給不一樣的Acceptor, Acceptor分別接受本身收到的value,就致使不一樣的value被選定。 => 一個提案被選定須要被半數以上的Acceptor接受 => 一個Acceptor必須可以接受不止一個提案 => 提案(Propersal) = [提案編號,value] => 必須保證全部被選定的提案都具備相同的value值 => P2:若是某個value爲v的提案被選定了,那麼每一個編號更高的被選定提案的value必須也是v。=> P2a:若是某個value爲v的提案被選定了,那麼每一個編號更高的被Acceptor接受的提案的value必須也是v。=> 分區不可用不符合 => P2b:若是某個value爲v的提案被選定了,那麼以後任何Proposer提出的編號更高的提案的value必須也是v。=> P2c:對於任意的N和V,若是提案[N, V]被提出,那麼存在一個半數以上的Acceptor組成的集合S,知足如下兩個條件中的任意一個: - S中每一個Acceptor都沒有接受過編號小於N的提案。 - S中Acceptor接受過的最大編號的提案的value爲V。=> Proposer生成提案,須要先詢問集羣中其餘的節點,肯定可被接受的value。=> Acceptor接受提案,一個Acceptor只要還沒有響應過任何編號大於N的Prepare請求,那麼他就能夠接受這個編號爲N的提案。
basic paxos是由client發起的同步過程,在兩階段返回前,client不能獲得成功的返回。引用wiki上的流程圖:
multi-paxos 在basic paxos的二階段上引入了一個機制,先運行一次完整的paxos算法選舉出leader,由leader處理全部的讀寫請求,而後省略掉prepare過程,讓本身看起來像一階段同樣。multi-paxos強leader狀態的流程圖:
流程圖中沒有了basic paxos的兩階段,變成了一個一階段的遞交協議:
一階段a:發起者(leader)直接告訴Acceptor,準備遞交協議號爲I+1的協議
一階段b:收到了大部分acceptor的回覆後(圖中是所有),acceptor就直接回復client協議成功寫入
Multi-Paxos能夠簡單的理解爲, 通過一輪的Basic Paxos, 成功獲得多數派accept的proposer即成爲leader(這個過程稱爲leader Election), 以後能夠經過lease機制, 保持這個leader的身份, 使得其餘proposer再也不發起提案, 這樣就進入了一個leader任期。在leader任期中, 因爲沒有了併發衝突, 這個leader在對後續的日誌進行投票時, 沒必要每次都向多數派詢問提案, 也沒必要執行prepare階段, 直接執行accept階段便可。
所以在Multi-Paxos中, 咱們將leader Election過程當中的prepare操做, 視爲對leader任期內將要寫的全部日誌的一次性prepare操做, 在leader任期內投票的全部日誌將攜帶有相同的提案編號. 須要強調的是, 爲了遵照Basic Paxos協議約束, 在leader Election的prepare階段, acceptor應答prepare成功的消息以前要先將此次prepare請求所攜帶的提案編號持久化到本地。
參考資料:
[https://en.wikipedia.org/wiki/Paxos_(computer_science)](https://en.wikipedia.org/wiki/Paxos_(computer_science)
http://www.infoq.com/cn/articles/weinxin-open-source-paxos-phxpaxos
與Paxos不一樣Raft強調的是易懂(Understandability),Raft和Paxos同樣只要保證n/2+1節點正常就可以提供服務;衆所周知但問題較爲複雜時能夠把問題分解爲幾個小問題來處理,Raft也使用了分而治之的思想把算法流程分爲三個子問題:選舉(Leader election)、日誌複製(Log replication)、安全性(Safety)三個子問題。
在任意的時間,每個服務器必定會處於如下三種狀態中的一個:Leader、Candidate、Follower。在正常狀況下,只有一個服務器是Leader,剩下的服務器是Follower。Follower們是被動的:他們不會發送任何請求,只是響應來自領導人和候選人的請求;Leader來處理全部來自客戶端的請求(若是一個客戶端與追隨者進行通訊,追隨者會將信息發送給領導人);Candidate是用來選取一個新的領導人的,在Leader肯定後降級爲Follower。以下圖爲各個角色的轉換流程:
在Raft中使用了一個能夠理解爲週期(第幾屆、任期)的概念,用Term做爲一個週期,每一個Term都是一個連續遞增的編號,每一輪選舉都是一個Term週期,在一個Term中只能產生一個Leader:
每一臺服務器都存儲着一個當前Term的數字,這個數字會單調的增長。當服務器之間進行通訊時,會互相交換當前Term值;若是一臺服務器的當前Term比其它服務器的小,則更新爲較大的值。若是一個候選人或者領導人意識到它的Term過期了,它會馬上轉換爲Follower狀態。若是一臺服務器收到的請求的Term是過期的,那麼它會拒絕這次請求。
RequestVote RPC:Candidate在選舉過程當中觸發,用於從Follower獲取選票。
AppendEntries RPC:Leader觸發的,爲的是複製日誌條目和提供一種心跳機制。
在Leader election中有兩個超時時間,分別爲:
Election timeout:Follower轉變爲Candidate的超時時間,是一個隨機值。在選舉Leader過程當中,若是一個Follower沒有在Election timeout時間內收到來自Leader的AppendEntries RPC請求或者Candidate的RequestVote RPC請求的話,則Follower會轉變爲Candidate,併發起選舉。
Heartbeate timeout:Leader存在時,Follower在Heartbeat timeout時間內沒有接收到Leader的AppendEntires請求,則認爲Leader已經下線,本身會轉變爲Candidate,發起選舉。
開始時,每一個節點都以Follower啓動,在第一輪時,因爲沒有收到任何的RPC請求,會觸發Election timeout,節點會自增Term,轉爲Candidate,發起選舉,不斷重試,直到知足如下任一條件:
得到超過半數Server的投票,轉換爲Leader,廣播Heartbeat
接收到合法Leader的AppendEntries RPC,轉換爲Follower
選舉超時,沒有Server選舉成功,自增currentTerm,從新選舉
Candidate在等待投票結果的過程當中,可能會接收到來自其它Leader的AppendEntries RPC。若是該Leader的Term不小於本地的currentTerm,則承認該Leader身份的合法性,主動降級爲Follower;反之,則維持Candidate身份,繼續等待投票結果;Candidate既沒有選舉成功,也沒有收到其它Leader的RPC請求,這種狀況通常出如今多個節點同時發起選舉,最終每一個Candidate都將超時。爲了減小衝突,這裏採起「隨機退讓」策略,每一個Candidate重啓選舉定時器(隨機值),大大下降了衝突機率。
Log Replication主要做用是用於保證節點的一致性,這階段所作的操做也是爲了保證一致性與高可用性;當Leader選舉出來後便開始負責客戶端的請求,全部事務(更新操做)請求都必須先通過Leader處理。
正常操做流程:
Client發送command給Leader
Leader追加command至本地log
Leader廣播AppendEntries RPC至Followers
一旦收到知足數量的日誌項committed成功的響應:
Leader應用對應的command至本地State Machine,並返回結果至Client
Leader經過後續Append EntriesRPC將committed日誌項通知到Follower
Follower收到committed日誌項後,將其應用至本地State Machine
安全性是用於保證每一個節點都執行相同序列的安全機制, Raft算法保證如下屬性時刻爲真:
Election Safety:在任意指定Term內,最多選舉出一個Leader
Leader Append-Only
Log Matching:若是兩個節點上的日誌項擁有相同的Index和Term,那麼這兩個節點[0, Index]範圍內的Log徹底一致
Leader Completeness:若是某個日誌項在某個Term被commit,那麼後續任意Term的Leader均擁有該日誌項
State Machine Safety
一旦某個server將某個日誌項應用於本地狀態機,之後全部server對於該偏移都將應用相同日誌項
集羣拓撲變化的意思是在運行過程當中多副本集羣的結構性變化,如增長/減小副本數、節點替換等 。爲了防止出現多主的狀況,raft使用了兩階段提交來處理。假設在Raft中,老集羣配置用Cold表示,新集羣配置用Cnew表示,整個集羣拓撲變化的流程以下:
當集羣成員配置改變時,leader收到人工發出的重配置命令從Cold切成Cnew;
Leader副本在本地生成一個新的log entry,其內容是Cold∪Cnew,表明當前時刻新舊拓撲配置共存,寫入本地日誌,同時將該log entry推送至其餘Follower節點;
Follower副本收到log entry後更新本地日誌,而且此時就以該配置做爲本身瞭解的全局拓撲結構;若是多數Follower確認了Cold∪Cnew這條日誌的時候,Leader就Commit這條log entry;
接下來Leader生成一條新的log entry,其內容是全新的配置Cnew,一樣將該log entry寫入本地日誌,同時推送到Follower上;
Follower收到新的配置日誌Cnew後,將其寫入日誌,而且今後刻起,就以該新的配置做爲系統拓撲,而且若是發現本身不在Cnew這個配置中會自動退出;
Leader收到多數Follower的確認消息之後,給客戶端發起命令執行成功的消息。
參考資料:
ZAB 協議是爲分佈式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。在 ZooKeeper 中,主要依賴 ZAB 協議來實現分佈式數據一致性,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集羣中各個副本之間的數據一致性。
Peer:節點。表明了系統中的進程,每每系統有多個進程,也就有多個節點提供服務
Quorum:多數。當有N個Peer,多數就表明Q(Q>N/2)個Peer
Leader:主節點,最多存在一個。表明zookeeper系統中主要的工做進程,Leader纔是真正處理全部zookeeper寫請求的節點,寫請求會從Leader廣播到Quorum Follower
Follower:從節點,能夠有多個。若是client對zookeeper發起一個讀請求,Follower能夠直接處理。若是client對zookeeper發起一個寫請求,Follower須要轉發到惟一的Leader,再有Leader處理併發起廣播
transaction:事務,一次寫請求就表明一次事務
zxid:事務id。zk爲了保證消息有序性,提出了事務編號這個概念。zxid是一個二元組,e表明選舉紀元,c表明事務的計數,同一紀元內每次出現寫請求,c自增。容易理解,紀元不變時,計數不斷增長,紀元變化時,計數清零。
acceptedEpoch:follower 已經接受的 leader 更改紀元的提議。
state:節點狀態,目前只有這三種:
election:節點處於選舉狀態
leading:當前節點是 leader,負責協調事務
following:當前節點是跟隨者,服從 leader 節點的命令
代碼實現中多了一種:observing 狀態,這是 Zookeeper 引入 Observer 以後加入的,Observer 不參與選舉,是隻讀節點,跟 ZAB 協議沒有關係節點的持久狀態。
history:當前節點接收到事務提議的 log。
lastZxid:history 中最近接收到的提議的 zxid (最大的)。
隨着系統啓動或者恢復,會經歷Zab協議中描述的以下四個階段:
Phase 0:Leader選舉,每一個peer從Quorum peer中選出本身心中的準leader。節點在一開始都處於選舉階段,只要有一個節點獲得超半數節點的票數,它就能夠當選準 leader。這一階段的目的是就是爲了選出一個準 leader,而後進入下一個階段。
Phase 1:發現,準leader從Quorum Follower中發現最新的數據,並覆蓋本身的過時數據。在這個階段,followers 跟準 leader 進行通訊,同步 followers 最近接收的事務提議。這一階段的主要目的是發現當前大多數節點接收的最新提議,而且準 leader 生成新的 epoch,讓 followers 接受,更新它們的 acceptedEpoch。
Phase 2:同步,準leader採用二階段提交的方式將本身的最新數據同步給Quorum Follower。完成這個步驟,準leader就轉爲正式leader。同步階段主要是利用 leader 前一階段得到的最新提議歷史,同步集羣中全部的副本。只有當 quorum 都同步完成,準 leader 纔會成爲真正的 leader。follower 只會接收 zxid 比本身的 lastZxid 大的提議。
Phase 3:廣播,Leader接受寫請求,並經過二階段提交的方式廣播給Quorum Follower。到了這個階段,Zookeeper 集羣才能正式對外提供事務服務,而且 leader 能夠進行消息廣播。同時若是有新的節點加入,還須要對新節點進行同步。ZAB 提交事務並不像 2PC 同樣須要所有 follower 都 ACK,只須要獲得 quorum (超過半數的節點)的 ACK 就能夠了。
真正apache zookeeper在實現上提出設想:優化leader選舉,直接選出最新的Peer做爲預備Leader,這樣就能將Phase 0和Phase 1合併,減小網絡上的開銷和多流程的複雜性。
實現上,協議被簡化爲三個階段
Fast Leader Election:從Quorum Peer中選出數據最新的peer做爲leader。該階段會選舉擁有最新提議歷史(lastZixd最大)的節點做爲 leader,這樣就省去了發現最新提議的步驟。這是基於擁有最新提議的節點也有最新提交記錄的前提。成爲 leader 的條件:選epoch最大的;epoch相等,選 zxid 最大的;epoch和zxid都相等,選擇myid最大的。節點在選舉開始都默認投票給本身,當接收其餘節點的選票時,會根據上面的條件更改本身的選票並從新發送選票給其餘節點,當有一個節點的得票超過半數,該節點會設置本身的狀態爲 leading,其餘節點會設置本身的狀態爲 following。
Recovery Phase:Leader將數據同步給Quorum Follower。
Broadcast Phase:Leader接受寫請求,並廣播給Quorum Follower。
對於選舉和恢復階段,zab算法須要確保兩件事:
已經處理過的提案不能被丟棄。
已經丟棄的提案不能被重複處理。
參考資料:
我的公衆號:啊駝