Paxos算法是萊斯利·蘭伯特(Leslie Lamport)1990年提出的一種基於消息傳遞的一致性算法。Paxos算法解決的問題是一個分佈式系統如何就某個值(決議)達成一致。在工程實踐意義上來講,就是能夠經過Paxos實現多副本一致性,分佈式鎖,名字管理,序列號分配等。好比,在一個分佈式數據庫系統中,若是各節點的初始狀態一致,每一個節點執行相同的操做序列,那麼他們最後能獲得一個一致的狀態。爲保證每一個節點執行相同的命令序列,須要在每一條指令上執行一個「一致性算法」以保證每一個節點看到的指令一致。本文首先會講原始的Paxos算法(Basic Paxos),主要描述二階段提交過程,而後會着重講Paxos算法的變種(Multi Paxos),它是對Basic Paxos的優化,並且更適合工程實踐,最後我會經過Q&A的方式,給出我在學習Paxos算法中的疑問,以及我對這些疑問的理解。html
概念與術語
Proposer:提議發起者,處理客戶端請求,將客戶端的請求發送到集羣中,以便決定這個值是否能夠被批准。
Acceptor:提議批准者,負責處理接收到的提議,他們的回覆就是一次投票,會存儲一些狀態來決定是否接收一個值。
replica:節點或者副本,分佈式系統中的一個server,通常是一臺單獨的物理機或者虛擬機,同時承擔paxos中的提議者和接收者角色。
ProposalId:每一個提議都有一個編號,編號高的提議優先級高。
Paxos Instance:Paxos中用來在多個節點之間對同一個值達成一致的過程,好比同一個日誌序列號:logIndex,不一樣的logIndex屬於不一樣的Paxos Instance。
acceptedProposal:在一個Paxos Instance內,已經接收過的提議
acceptedValue:在一個Paxos Instance內,已經接收過的提議對應的值。
minProposal:在一個Paxos Instance內,當前接收的最小提議值,會不斷更新node
Basic-Paxos算法
基於Paxos協議構建的系統,只須要系統中超過半數的節點在線且相互通訊正常便可正常對外提供服務。它的核心實現Paxos Instance主要包括兩個階段:準備階段(prepare phase)和提議階段(accept phase)。以下圖所示:算法
1.獲取一個ProposalId,爲了保證ProposalId遞增,能夠採用時間戳+serverId方式生成;
2.提議者向全部節點廣播prepare(n)請求;
3.接收者比較n和minProposal,若是n>minProposal,表示有更新的提議,minProposal=n;不然將(acceptedProposal,acceptedValue)返回;
4.提議者接收到過半數請求後,若是發現有acceptedValue返回,表示有更新的提議,保存acceptedValue到本地,而後跳轉1,生成一個更高的提議;
5.到這裏表示在當前paxos instance內,沒有優先級更高的提議,能夠進入第二階段,廣播accept(n,value)到全部節點;
6.接收者比較n和minProposal,若是n>=minProposal,則acceptedProposal=minProposal=n,acceptedValue=value,本地持久化後,返回;
不然,返回minProposal
7.提議者接收到過半數請求後,若是發現有返回值>n,表示有更新的提議,跳轉1;不然value達成一致。
從上述流程可知,併發狀況下,可能會出現第4步或者第7步頻繁重試的狀況,致使性能低下,更嚴重者可能致使永遠都沒法達成一致的狀況,就是所謂的「活鎖」,以下圖所示:sql
1.S1做爲提議者,發起prepare(3.1),並在S1,S2和S3達成多數派;
2.隨後S5做爲提議者 ,發起了prepare(3.5),並在S3,S4和S5達成多數派;
3.S1發起accept(3.1,value1),因爲S3上提議 3.5>3.1,致使accept請求沒法達成多數派,S1嘗試從新生成提議
4.S1發起prepare(4.1),並在S1,S2和S3達成多數派
5.S5發起accpet(3.5,value5),因爲S3上提議4.1>3.5,致使accept請求沒法達成多數派,S5嘗試從新生成提議
6.S5發起prepare(5.5),並在S3,S4和S5達成多數派,致使後續的S1發起的accept(4.1,value1)失敗數據庫
......promise
prepare階段的做用
從Basic-Paxos的描述可知,須要經過兩階段來最終肯定一個值,因爲輪迴多,致使性能低下,至少兩次網絡RTT。那麼prepare階段可否省去?以下圖所示:安全
1.S1首先發起accept(1,red),並在S1,S2和S3達成多數派,red在S1,S2,S3上持久化
2.隨後S5發起accept(5,blue),對於S3而言,因爲接收到更新的提議,會將acceptedValue值改成blue
3.那麼S3,S4和S5達成多數派,blue在S3,S4和S5持久化
4.最後的結果是,S1和S2的值是red,而S3,S4和S5的值是blue,沒有達成一致。性能優化
因此兩階段必不可少,Prepare階段的做用是阻塞舊的提議,而且返回已經接收到的acceptedProposal。同時也能夠看到的是,假設只有S1提議,則不會出現問題,這就是咱們下面要講的Multi-Paxos。網絡
Multi-paxos算法
Paxos是對一個值達成一致,Multi-Paxos是連續多個paxos instance來對多個值達成一致,這裏最核心的緣由是multi-paxos協議中有一個Leader。Leader是系統中惟一的Proposal,在lease租約週期內全部提案都有相同的ProposalId,能夠跳過prepare階段,議案只有accept過程,一個ProposalId能夠對應多個Value,因此稱爲Multi-Paxos。併發
選舉
首先咱們須要有一個leader,其實選主的實質也是一次Paxos算法的過程,只不過此次Paxos肯定的「誰是leader」這個值。因爲任何一個節點均可以發起提議,在併發狀況下,可能會出現多主的狀況,好比A,B前後當選爲leader。爲了不頻繁選主,當選leader的節點要立刻樹立本身的leader權威(讓其它節點知道它是leader),寫一條特殊日誌(start-working日誌)確認其身份。根據多數派原則,只有一個leader的startworking日誌能夠達成多數派。leader確認身份後,能夠經過了lease機制(租約)維持本身的leader身份,使得其它proposal再也不發起提案,這樣就進入了leader任期,因爲沒有併發衝突,所以能夠跳過prepare階段,直接進入accept階段。經過分析可知,選出leader後,leader任期內的全部日誌都只須要一個網絡RTT(Round Trip Time)便可達成一致。
新主恢復流程
因爲Paxos中並無限制,任何節點均可以參與選主並最終成爲leader,這就沒法保證新選出的leader包含了全部日誌,可能存在空洞,所以在真正提供服務前,還存在一個獲取全部已提交日誌的恢復過程。新主向全部成員查詢最大logId的請求,收到多數派響應後,選擇最大的logId做爲日誌恢復結束點,這裏多數派的意義在於恢復結束點包含了全部達成一致的日誌,固然也可能包含了沒有達成多數派的日誌。拿到logId後,從頭開始對每一個logId逐條進行paxos協議,由於在新主得到全部日誌以前,系統是沒法提供服務的。爲了優化,引入了confirm機制,就是將已經達成一致的logId告訴其它acceptor,acceptor寫一條confirm日誌到日誌文件中。那麼新主在重啓後,掃描本地日誌,對於已經擁有confirm日誌的log,就不會從新發起paxos了。一樣的,在響應客戶端請求時,對於沒有confirm日誌的log,須要從新發起一輪paxos。因爲沒有嚴格要求confirm日誌的位置,能夠批量發送。爲了確保重啓時,不須要對太多已提價的log進行paxos,須要將confirm日誌與最新提交的logId保持必定的距離。
性能優化
Basic-Paxos一第二天志確認,須要至少2次磁盤寫操做(prepare,promise)和2次網絡RTT(prepare,promise)。Multi-Paxos利用一階段提交(省去Prepare階段),將一第二天志確認縮短爲一個RTT和一次磁盤寫;經過confirm機制,能夠縮短新主的恢復時間。爲了提升性能,咱們還能夠實現一批日誌做爲一個組提交,要麼成功一批,要麼都不成功,這點相似於group-commit,經過RT換取吞吐量。
安全性(異常處理)
1.Leader異常
Leader在任期內,須要按期給各個節點發送心跳,已告知它還活着(正常工做),若是一個節點在超時時間內仍然沒有收到心跳,它會嘗試發起選主流程。Leader異常了,則全部的節點前後都會出現超時,進入選主流程,選出新的主,而後新主進入恢復流程,最後再對外提供服務。咱們一般所說的異常包括如下三類:
(1).進程crash(OS crash)
Leader進程crash和Os crash相似,只要重啓時間大於心跳超時時間都會致使節點認爲leader掛了,觸發從新選主流程。
(2).節點網絡異常(節點所在網絡分區)
Leader網絡異常一樣會致使其它節點收不到心跳,但有可能leader是活着的,只不過發生了網絡抖動,所以心跳超時不能設置的過短,不然容易由於網絡抖動形成頻繁選主。另一種狀況是,節點所在的IDC發生了分區,則同一個IDC的節點相互還能夠通訊,若是IDC中節點能構成多數派,則正常對外服務,若是不能,好比總共4個節點,兩個IDC,發生分區後會發現任何一個IDC都沒法達成多數派,致使沒法選出主的問題。所以通常Paxos節點數都是奇數個,並且在部署節點時,IDC節點的分佈也要考慮。
(3).磁盤故障
前面兩種異常,磁盤都是OK的,即已接收到的日誌以及對應confirm日誌都在。若是磁盤故障了,節點再加入就相似於一個新節點,上面沒有任何日誌和Proposal信息。這種狀況會致使一個問題就是,這個節點可能會promise一個比已經promise過的最大proposalID更小的proposal,這就違背了Paxos原則。所以重啓後,節點不能參與Paxos Instance,它須要先追上Leader,當觀察到一次完整的paxos instance時該節點結束不能promise/ack狀態。
2.Follower異常(宕機,磁盤損壞等)
對於Follower異常,則處理要簡單的多,由於follower自己不對外提供服務(日誌可能不全),對於leader而言,只要能達成多數派,就能夠對外提供服務。follower重啓後,沒有promise能力,直到追上leader爲止。
Q&A
1.Paxos協議數據同步方式相對於基於傳統1主N備的同步方式有啥區別?
通常狀況下,傳統數據庫的高可用都是基於主備來實現,1主1備2個副本,主庫crash後,經過HA工具來進行切換,提高備庫爲主庫。在強一致場景下,複製能夠開啓強同步,Oracle和Mysql都是相似的複製模式。可是若是備庫網絡抖動,或者crash,都會致使日誌同步失敗,服務不可用。爲此,能夠引入1主N備的多副本形式,咱們對比都是3副本的狀況,一個是基於傳統的1主2備,另外一種基於paxos的1主2備。傳統的1主兩備,進行日誌同步時,只要有一個副本接收到日誌並就持久化成功,就能夠返回,在必定程度上解決了網絡抖動和備庫crash問題。但若是主庫出問題後,仍是要藉助於HA工具來進行切換,那麼HA切換工具的可用性如何來保證又成爲一個問題。基於Paxos的多副本同步實際上是在1主N備的基礎上引入了一致性協議,這樣整個系統的可用性徹底有3個副本控制,不須要額外的HA工具。而實際上,不少系統爲了保證多節點HA工具獲取主備信息的一致性,採用了zookeeper等第三方接口來實現分佈式鎖,其實本質也是基於Paxos來實現的。
我這裏以MySQL的主備複製一套體系爲例來具體說明傳統的主備保持強一致性的一些問題。整個系統中主要包含如下幾種角色:Master,Slave,Zookeeper-Service(zk),HA-Console(HA),Zookeeper-Agent(Agent)
Master,Slave:分別表示主節點和備節點,主節點提供讀寫服務,備節點能夠提供讀服務,或者徹底用於容災。
Zookeeper-Service(zk):分佈式一致性服務,負責管理Master/Slave節點的存活信息和切換信息。zk基於zab協議,zab協議是一種一致性協議,與paxos,raft協議相似,它主要有兩種模式,包括恢復模式(選主)和廣播模式(同步)。通常zk包含N個節點(zk-node),只要有超過半數的zk-node存活且相互連通,則zk能夠對外提供一致性服務。
HA-Console:切換工具,負責具體的切換流程
Zookeeper-Agent(Agent):Master/Slave實例上的監聽進程,與監聽的實例保持心跳,維護Master/Slave的狀態,每一個實例有一個對應的Agent。大概工做流程以下:
(1).Master/Slave正常啓動並搭建好了複製關係,對應的Agent會調用zk接口去註冊alive節點信息,假設分別爲A和B。
(2).若是此時Master Crash,則實例對應的Agent發現心跳失敗,若是重試幾回後仍然失敗,則將調用zk接口註銷掉A節點信息。
(3).HA工具經過zk接口比較兩次的節點信息,發現少了A節點,表示A可能不存在了,須要切換,嘗試鏈接A,若是仍然不通,註冊A的dead節點,並開始切換流程。
(4).HA工具讀取配置信息,找到對應的Slave節點B,(更改讀寫比配置信息,設置B提供寫),打開寫。
(5).應用程序經過拉取最新的配置信息,得知新主B,新的寫入會寫入B。
前面幾部基本介紹了MySQL藉助zk實現高可用的流程,因爲zk-node能夠多地部署,HA無狀態,所以能夠很容易實現同城或者是異地的高可用系統,而且動態可擴展,一個HA節點能夠同時管理多個Master/Slave的切換。那麼能保證一致性嗎?前面提到的Agent除了作監聽,還有一個做用是儘量保持主備一致,而且不丟數據。
(6).假設此時A節點重啓,Agent檢測到,經過zk接口發現A節點在dead目錄下,表示被切換過,須要kill上面的全部鏈接,並回滾crash時A比B多的binlog,爲了儘量的少丟數據,而後再開啓binlog後,將這部分數據重作。這裏要注意rollback和replay都在old-Master上面進行,rollback時須要關閉binlog,而replay須要開啓binlog,保證這部分數據能流向new-Master。
(7).從第6步來看,能夠必定程度上保證主備一致性,可是進行rollback和replay時,其實是往new-Slave上寫數據,這必定程度上形成了雙寫,若是此時new—Master也在寫同一條記錄,可能會致使寫覆蓋等問題。
(8).若是開啓半同步呢?old-Master crash時,仍然可能比old-Slave多一個group的binlog,因此仍然須要藉助於rollback和replay,依然避免不了雙寫,因此也不能作到嚴格意義上的強一致。
2.分佈式事務與Paxos協議的關係?
在數據庫領域,提到分佈式系統,就會提到分佈式事務。Paxos協議與分佈式事務並非同一層面的東西。分佈式事務的做用是保證跨節點事務的原子性,涉及事務的節點要麼都提交(執行成功),要麼都不提交(回滾)。分佈式事務的一致性一般經過2PC來保證(Two-Phase Commit, 2PC),這裏面涉及到一個協調者和若干個參與者。第一階段,協調者詢問參與者事務是否能夠執行,參與者回覆贊成(本地執行成功),回覆取消(本地執行失敗)。第二階段,協調者根據第一階段的投票結果進行決策,當且僅當全部的參與者贊成提交事務時才能提交,不然回滾。2PC的最大問題是,協調者是單點(須要有一個備用節點),另外協議是阻塞協議,任何一個參與者故障,都須要等待(能夠經過加入超時機制)。Paxos協議用於解決多個副本之間的一致性問題。好比日誌同步,保證各個節點的日誌一致性,或者選主(主故障狀況下),保證投票達成一致,選主的惟一性。簡而言之,2PC用於保證多個數據分片上事務的原子性,Paxos協議用於保證同一個數據分片在多個副本的一致性,因此二者能夠是互補的關係,毫不是替代關係。對於2PC協調者單點問題,能夠利用Paxos協議解決,當協調者出問題時,選一個新的協調者繼續提供服務。工程實踐中,Google Spanner,Google Chubby就是利用Paxos來實現多副本日誌同步。
3.如何將Paxos應用於傳統的數據庫複製協議中?
複製協議至關因而對Paxos的定製應用,經過對一系列日誌進行投票確認達成多數派,就至關於日誌已經在多數派持久化成功。副本經過應用已經持久化的日誌,實現與Master節點同步。因爲數據庫ACID特性,本質是由一個一致的狀態到另一個一致的狀態,每次事務操做都是對應數據庫狀態的變動,並生成一條日誌。因爲client操做有前後順序,所以須要保證日誌的前後的順序,在任何副本中,不只僅要保證全部日誌都持久化了,並且要保證順序。對於每條日誌,經過一個logID標示,logID嚴格遞增(標示順序),由leader對每一個日誌進行投票達成多數派,若是中途發生了leader切換,對於新leader中logID的「空洞」,須要從新投票,確認日誌的有效性。
4.Multi-Paxos的非leader節點能夠提供服務嗎?
Multi-Paxos協議中只有leader確保包含了全部已經已經持久化的日誌,固然本地已經持久化的日誌不必定達成了多數派,所以對於沒有confirm的日誌,須要再進行一次投票,而後將最新的結果返回給client。而非leader節點不必定有全部最新的數據,須要經過leader確認,因此通常工程實現中,全部的讀寫服務都由leader提供。
5.客戶端請求過程當中失敗了,如何處理?
client向leader發起一次請求,leader在返回前crash了。對於client而言,此次操做可能成功也可能失敗。所以client須要檢查操做的結果,肯定是否要從新操做。若是leader在本地持久化後,並無達成多數派時就crash,新leader首先會從各個副本獲取最大的logID做爲恢復結束點,對於它本地沒有confirm的日誌進行Paxos確認,若是此時達成多數派,則應用成功,若是沒有則不該用。client進行檢查時,會知道它的操做是否成功。固然具體工程實踐中,這裏面涉及到client超時時間,以及選主的時間和日誌恢復時間。
參考文檔
https://ramcloud.stanford.edu/~ongaro/userstudy/paxos.pdf
http://www.cs.utexas.edu/users/lorenzo/corsi/cs380d/papers/paper2-1.pdf
http://research.microsoft.com/en-us/um/people/lamport/pubs/paxos-simple.pdf
https://zhuanlan.zhihu.com/p/20417442
http://my.oschina.net/hgfdoing/blog/666781
http://www.cnblogs.com/foxmailed/p/5487533.html
http://www.wtoutiao.com/p/1a7mSx6.html