1. 程式人生 > >Paxos的通俗理解以及在資料庫高可用上的使用

Paxos的通俗理解以及在資料庫高可用上的使用

近期大家都在討論Paxos演算法,我看了很多網上的文章,總覺得有些晦澀難懂,經過一段時間研究,對Paxos有了一些理解,在這裡總結一下,希望能拋磚引玉。

1、為什麼需要Paxos

Paxos要解決的問題,是分散式系統中的一致性問題。那麼到底什麼是“分散式系統中的一致性問題”呢?在分散式系統中,為了保證資料的高可用,通常,我們會將資料保留多個副本(replica),這些副本會放置在不同的物理的機器上。副本要保持一致,那麼,所有副本的更新序列就要保持一致。因為資料的增刪改查操作一般都存在多個客戶端併發操作,到底哪個客戶端先做,哪個客戶端後做,更新順序要保證。如果不是分散式,那麼可以通過加鎖的方法,誰先申請到鎖誰就先操作,但這就存在單點問題。Paxos協議主要有兩種用法:一種用法是用來實現全域性的鎖服務或者命名和配置服務,例如Google Chubby以及Apache ZooKeeper。另外一種用法是用它來將使用者資料複製到多個數據中心,例如Google Megastore以及Google Spanner。

以一個分散式的KV資料庫為例,假設資料庫對外提供2種操作Put和Get,具體架構如下:

在這樣一個架構下,可以通過多臺server組成叢集來避免單點問題。我們需要解決的是3臺server必須保持同步,也就是說,如果向叢集傳送請求Put(“a”,1)併成功,那麼整個叢集任意一臺server必須含有(“a”,1)。另外假設此時多個client併發訪問叢集,不同客戶端的請求可能會落入到不同的server機器上,比如併發有Put(“b”,2)和Put(“c”,3),我們需要保證哪個客戶端請求先做,哪個後做,保證更新順序,這就是Paxos演算法需要解決的問題。

2、Paxos演算法

我們先來簡單描述一下Paxos演算法,對演算法本身有一個直觀的認識,然後再結合後面的例子來進一步理解。

在Paxos演算法中,主要有3種角色:

  • Proposer:提議者
  • Acceptor:決策者
  • Learner:最終決策學習者

實現的時候往往採用一組固定數目的Server,每個Server同時擔任上述三個角色。

Paxos演算法分為以下三個階段:

1、Prepare階段

(1)Proposer向大多數Acceptor發起Proposal(epochNo,value)的Prepare請求。

(2)Acceptor收到Prepare請求,如果epochNo比之前接收到的小,直接拒絕;如果epochNo比之前已經接收的大,就將已經接收到的epochNo最大的Proposal返回到Proposer。

(3)Proposer發起的Proposal至少要收到大多數以上的Acceptor的Prepare應答後,才能進入接下來的Accept階段,否則需要重新進行Prepare階段向大多數Acceptor發起Prepare請求。

2、Accept階段:

(1)Proposer收到大多數的Acceptor的Prepare應答後,看Acceptor是否已經有被接受的Proposal。如果沒有已經接受的Proposal,就自己提出一個Proposal,發起Accept請求;如果已經有被接受的Proposal,就從中選出epochNo最大的Proposal,發起對該Proposal的Accept請求。

(2)Acceptor收到請求後,如果該Proposal的epochNo比它最後一次應答Prepare請求的epochNo要大,那麼就接受該請求;否則拒絕該請求。

3、Learn階段:

所有Acceptor接受的Proposal要不斷通知Learner,或者Learner主動去查詢,一旦Learner確認Proposal被大多數的Acceptor接受,那麼表示這個Proposal的Value被Chosen,Learner就可以學習這個Proposal的Value,同時自己的Sever上就不再受理Proposor的請求。

我喜歡通過例子來理解理論,理論源於生活,下面我以生活中的例子來進行該演算法的描述。

假設一群驢友決定端午去旅遊,驢友遍佈全國各地,一共10人,為了能達成一致,這10個人另外找5個作為隊長。5個隊長之間相互不通訊,只跟10個驢友發簡訊。

第一階段(申請階段),驢友發簡訊給5個隊長,申請與隊長進行溝通。隊長在任何時刻只能與一個驢友溝通。傳送的每條簡訊都帶有時間,隊長採用的原則是同意與簡訊傳送時間最新的驢友溝通,如果出現更新的簡訊,則與簡訊更新的驢友溝通。至少大多數隊長同意溝通了,這個驢友才能進入第二階段實質性溝通。

第二階段(溝通階段),獲得溝通權的驢友A收到隊長們給他發的旅遊地,可能有幾種情況。

  • 第一種情況:溝通的隊長們全部都還沒有決定到底去哪裡旅遊,此刻驢友A會把自己想去的旅遊地發給隊長們(比如馬爾地夫),結果可能大多數隊長同意了,整個過程執行完畢,就是去馬爾地夫旅遊了,其他的驢友遲早會知道。除此之外就表明失敗了,可能隊長沒有回覆(跟女友打電話去了),可能被其他驢友搶佔溝通權了(上面說過隊長只跟最新的簡訊的人進行溝通)。如果失敗了,A需要重新開始第一階段申請,重新給隊長們發簡訊申請溝通權。
  • 第二種情況:至少有一個隊長已經決定旅遊地了,這個時候A會收到不同隊長決定的多個旅遊地,這些旅遊地是不同隊長跟不同驢友在不同時間做的決定。A會先看看有的旅遊地是不是被大多數(半數以上)隊長同意了,如果有(這裡假設3個隊長決定去三亞,一個去拉薩,另外可能某種原因沒搭理),那證明整個決定過程已經達成一致了,A收拾收拾去三亞吧,結束!
  • 如果都沒有達到半數(比如2個去三亞,1個去拉薩,1個去昆明,1個沒搭理),這時候A可能想去馬爾地夫,但也不按照自己意願亂來了(這裡是Paxos的關鍵所在,後者認可前者,否則整個過程無止境了),A會根據收到隊長的所有旅遊地中找到最新的那個決定地(比如去昆明是那個隊長是1分鐘前決定的,去拉薩的隊長是半小時前決定的,去三亞的隊長是1小時前決定的),於是A頂最新的決定,去昆明。這時候去昆明的決定又更新了,這樣下一個搶到溝通權的驢友也很大可能會頂去昆明,這樣決定去昆明的隊長會越來越多。
  • 一旦某個時刻大多數(半數以上)隊長都同意了去某個地點,比如去昆明,後續獲得溝通權的驢友B會發現大多數隊長都決定去昆明瞭,它也會服從,最終所有的驢友都達成一致去昆明。

Paxos的基本思想大致就是上面過程,Paxos利用的是選舉,少數服從多數的思想,只要N個(N為奇數,至少大於等於3)節點中,有[N/2]+1(這裡N/2為向下取整)或以上個節點同意了某個決定,則認為系統達到了一致,這樣的話,客戶端不必與所有伺服器通訊,選擇與大部分通訊即可;也無需伺服器都全部處於工作狀態,有一些伺服器掛掉,只有保證半數以上存活著,整個過程也能持續下去,容錯性相當好。

Paxos中的Acceptor相當於上面的隊長,Proposer相當於上面的驢友,epochNo號就相當於例子中申請簡訊的傳送時間。Paxos最消耗時間的地方就在於需要半數以上同意溝通了才能進入第二步,試想一下,一開始,所有驢友就給隊長狂發簡訊,每個隊長收到的最新簡訊的是不同驢友,這樣,就難以達到半數以上都同意與某個驢友溝通的狀態,為了減小這個時間,Paxos還有Fast Paxos的改進等等,這裡不再細說。另外,paxos並不指代一個協議,而是一類協議的統稱,比較常見的paxos類協議有:basic paxos和multi-paxos,這裡的例子說的是basic paxos,basic paxos協議較複雜,且相對效率較低,所以現在所有和paxos有關的協議的系統,一般都是基於multi-paxos來實現的,有興趣瞭解可以參考文章https://zhuanlan.zhihu.com/p/25664121

3、Paxos在資料庫高可用上的使用

作為dba,為了實現高可用,最常用的高可用方式是主從模式,以mysql為例,主要有幾種

(1)強同步複製,binlog同步到從庫之後,從庫返回給主庫ok之後才能返回給客戶端提交成功,這就有個問題,一旦主從之間網路出現抖動,甚至從庫宕機,則主庫就無法再繼續提供服務,這種模式實現了資料的強一致,但是犧牲了服務的可用性。

(2)非同步複製,主庫寫本地成功後,立刻返回給客戶端說成功,無需等待從庫應答,這樣一旦主庫宕機,可能會有少量的日誌沒有同步到從庫造成部分資料丟失,這種模式可用性很好,但是犧牲了資料的一致性。

(3)半同步複製,這種模式是一個折中,主要指至少有一個從庫節點收到日誌返回給主庫ok之後,這是就可以返回給客戶端提交成功,當網路環境不好的時候可能退化為非同步複製。

另外主從模式還有一個無法繞過的問題,就是選主,為了主從模式的選主,長期以來也誕生了很多種高可用方案,MMM,MHA,中間層等等,但顯然理論和思路都不是最先進的。

總結一下,針對主從方式處理資料庫高可用有諸多缺陷,要想改進這種資料同步方式,可以梳理資料庫高可用的幾點需求:

  1. 資料不丟失
  2. 服務持續可用性
  3. 自動選主
  4. 自動容錯

使用paxos協議的日誌同步就可以實現以上的三個需求,當然paxos協議需要依賴一個基本假設,主備之間有多數派機器(N/2+1)是存活且它們之間的網路通訊正常,如果不滿足這個條件,則無法啟動服務,資料也無法寫入和讀取。

所以我們可以使用paxos進行redolog或者binlog的複製,從而保證高可用強一致的叢集,主從的切換也不需要擔心,只需要有個vip,後端對映後面資料庫的多點就行,paxos會自動保證多點的一致性寫入,業界阿里雲使用paxos或者raft來做的企業三節點的mysql叢集。

原文來自微信公眾號:Qunar技術沙龍