Paxos沉思錄

最近在思考一致性的問題,網上有很多這方面的資料了,這里談談我對一致性以及paxos算法的理解。

1 一致性

什么是一致性,所謂一致性就是數據保持一致,在分布式系統中,可以理解為多個節點中數據的值是一致的。在單機系統中多線程程序其實也有一致性的問題,兩個線程對一個變量的訪問,在JAVA程序中我們有volatile關鍵字保證內存的一致性,也就是說當一個線程修改一個共享變量時,我們要確保另外一個線程能讀到這個修改的值,當然我們還有有其他各種同步機制。在單機上的一致性這個其實非常好理解。

在分布式系統中,為了提供可用性,通常我們的數據在不同節點上會有多個備份,我們是沒辦法保證對所有副本同時更新,這樣不同client在讀不同副本的時候就可能出現讀取的值不一致的情形。根據CAP理論,一致性,可用性,分區容忍性,三者只能取其二,三者不可兼得。通常分布式系統都要容忍分區(即分區隔離情況下也必須能工作),這樣在工程實踐上就變成了一致性和可用性只能取其一。理論上講,如果保證100%可用性的情況下不可能達到強一致,但是這并不意味著就沒有了一致性,一致性可以分為幾種:強一致,弱一致,最終一致性等等。

強一致-總是能讀到最近一次寫的值;

弱一致性-可能讀到舊(Stale)的值;

最終一致性-在一段時間窗口內可能讀到舊的值,最終會讀到新的值。

對于應用開發人員來說都是希望強一致的,我寫下去的值我希望立刻能讀到,但是強一致系統往往性能不太好(相對而言), 于是就只能tradeoff,幾乎所有流行的NoSQL系統為了追求性能,都犧牲了部分一致性,實現成一個弱一致或最終一致性系統,

即BASE(BasicallyAvailable,Soft state,Eventualconsistency),BASE的含義就是指“NoSQL數據庫設計可以通過犧牲一定的數據一致性和容錯性來換取高性能的保持甚至提高”。

我們看看工業界的存儲系統,其實可以分為CP系統以及AP系統。追求極致可用性(AP)的常見系統包括:

AmazonS3

AmazonDynamo DB

MongoDB/Redis為代表的NoSQL

……

追求強一致的CP系統,比如:

GoogleMegastore / Spanner

MicrosoftAzure Storage

TiDB/CockroachDB

AmazonAurora

……

2 如何實現強一致性

2.1 協議

分布式系統實現強一致的需要某種協議來保證,經典的兩階段提交2PC雖然解決了強一致的問題,但是可用性很差,因為2PC在協調者(TM)宕機時無法決定事務狀態,系統阻塞,需要等待協調者(TM)恢復才能繼續下去。

在工作中會議室預定系統就是一個2PC系統,會議發起方(TM)會詢問所有會議參與者是否有空,如果所有參會者都有空(OK),那么提交(commit)此次預訂,此次會議預定成功。如果有任意一個參會者(RM)沒空,那次此次預定失敗。這里有個問題是,假設在與會者回應之后,會議發起方中途有事離開,那么與會者是沒法知道此次預定是否成功的,沒法完成也沒法中途取消,系統會阻塞,必須等等發起方回來之后才能繼續下去。

后續改良版的三階段提交(3PC)增加了一個中間狀態方便判斷事務狀態,協調者宕機,選出新的協調者,新的協調者不用等宕機者恢復就能決定事務狀態,但是在網絡分區的情況下,可能出現不一致的問題。比如在某些情況下可能會出現,比如兩個節點都宣稱自己是新的協調者的情況,這時候3PC仍然沒有提出一個好的解決辦法。因此可以說2PC/3PC都存在一些先天缺陷,2PC有可用性的問題,3PC有一致性的缺陷。于是Lamport大神提出的Paxos協議就可以派上用場,發揮它的威力了。

2.2 Paxos協議

Paxos協議是Lamport大神在80年代提出的解決分布式一致性多個節點之間就某個值達成一致的經典通信協議。協議也分為兩個階段:

第一階段P1 Prepare階段

P1a:Proposer發送Prepare請求

Proposer發送全局唯一且遞增的提案ID(Proposal ID或者叫Ballot),向所有節點(即Acceptor)發送Prepare Request,這里無需提交提案內容,只需要攜帶Proposal ID即可。

P1b : Acceptor應答Prepare Request

Acceptor收到Prepare Request之后,檢查自己之前是否接受過大于等于該提案ID(ProposalID或者Ballot)的請求,如果沒有,則Accept該Prepare請求,并且做出以下兩個承諾:

第二階段P2 Accept階段

P2a:Proposer發送Accept請求

首先,Proposer根據P1b結果決定是否繼續到下一階段,即第二階段。如果在P1b階段沒有收到多數Acceptor的相應,此次Paxos實例結束。如果收到了多數Acceptor節點應答的PrepareResponse,才會進入到P2a階段。在P2a階段,proposal發起Accept請求,該Accept請求除了攜帶當前ProposalID,即在P1階段被多數節點接受的Proposal ID,還需要攜帶提案內容。注意,此處提案內容不是隨心所欲,提案內容的生成是有規則的,這個規則就是:

Proposer收集到多數派應答的PrepareResponse后,從中選擇proposalid最大的提案內容,作為要發起Accept的提案,如果這個提案為空,則proposer可以隨意決定提案內容.

這個規則非常重要,是paxos算法保證準確性的最重要的原則,需要好好理解。

這里再思考一下,為什么需要兩個階段?第一個階段Prepare的目的是什么?其實可以這樣想,兩個階段目的就是是為了解決提案沖突,試想如果只用一個階段一次提交提交顯然無法達到一致的狀態。而兩個階段各有作用,第一個階段Prepare的作用其實就是拿到一個授權,誰的Prepare ID最大誰就有權利去發起第二個階段的accept請求。而第二個階段,有權利的節點發生accept請求,該請求內容可能不是自己的,而是從所有已經accept中的提案選出提案號最大的那個,這就保證了最終被接受的提案的唯一性,換句話說,如果一個提案被大多數節點同意(accepted)了,那么該提案一定會被最終popugate到所有節點,而這樣的提案只可能有一個,這樣就保證了正確性(safety)。

可能這樣解釋還是很抽象,舉個生活中的例子。很多同事中午吃飯都有一個疑惑,不知道午飯到哪里吃,一群人需要決定到哪家餐館吃午飯,對這個問題達成一致,這其實就是一個典型的一致性問題。讓我們用paxos協議來決定午飯到哪里吃。假設有5位同學A,B,C,D,E,有這樣幾種情形:

情形一:

A提議說:"我來說個餐廳吧?"(P1a)

BCDE四個同學自己也沒有想法,那就同意吧:"聽你的。"(P1b)

A說:“去吃望湘源吧?”(P2a)

BC沒有想法:“好吧,就吃望湘源”。(P2b)

DE沒有說話。A看看大家的結果,BC同意,包括自己總共3個人同意,已經達到多數票,那就這樣決定了,然后A告訴所有人中午一起去吃望湘源了。

情形二:

A提議說:"我來說個餐廳吧?"(P1a)(Ballot=1)

B,C說:“好啊”。(P1b)

但是E不同意了,E馬上說:“不行,昨天吃你推薦的望湘源把我辣死啦,還是不聽你的了”。(P1b,A的Prepare請求被E拒絕)

A看看其他3個人沒有反對自己,仍然固執地提出自己的想法:“我們今天不吃辣的,吃本幫菜,豐收日怎么樣?”。(P2a)

B表示同意:“豐收日不錯的”(P2b)

E把手舉得高高的說:“還是我來推薦個人氣餐廳吧”(P1a,Ballot=2)

C,D兩位同學說:“好啊,你說吃啥?”(P1b,由于C,D響應了E的請求,將不再響應A的請求)

B說:“我已經答應A去吃豐收日了耶”

E看看提議號最高并且已經接受過的應答中(Ballot=1優先級最高),B已經接受請求了,那勉為其難的說:“好吧,豐收日就豐收日吧”

C,D:“行!”

于是大家就愉快地去豐收日了。

注意這里很重要的一點,也是理解paxos的核心,就是按照提案生成規則,當E看到別人已經接受的請求了,就不能提出自己的請求。但是假設E沒有聽到B的回答,而是只聽到C,D同意的響應,E仍然可以提出自己的想法。這兩種情況,雖然結果不一樣,但是都達成一致了。

上述是basic paxos的理論模型,在工程實踐上實現paxos是有很多坑,google的megastore和chubby,以及后來的spanner實現都采用了paxos,在其論文'Paxos made live'也描述了工程實現上遇到的問題。

3 Leader or not Leader

經典的paxos協議是沒有leader的概念的,各個角色完全對等,任何節點都可以發起proposal請求,但這樣的實現往往性能不會太好。在具體工程應用中大多會考慮Leader based的paxos實現,完全沒有leader的paxos目前僅僅存在于理論上。根據Leader的作用,具體可以分為兩類:強leader和弱leader。

所謂leader,實際就將第一階段的prepare的權利賦予某一個節點,即Leader,又稱coordinator,或者叫Master。這樣由于系統中只有一個節點有發起提議的權利,就無需運行paxos的第一階段P1,直接進行第二階段accept,除非有沖突發生。所謂沖突就是accept過程發現有其他并發請求,這樣就必須回退到第一階段。另外在原Leader節點宕機,就需要重新選Leader,當然重新選Leader期間系統是不可服務的。Multi-Paxos是基于強Leader的實現,依靠leader進行日志復制同步和恢復。

在Paxos早期應用中 像Google的Meagstore是最早將Paxos協議大規模應用在工程實踐中的系統,從Megastore論文可以看出其paxos實現,其弱化了Leader(coordinator)的作用,其coorinator只是用來保存哪些replica是up-to-date的,如果是,則直接進行local read,不需要再走paxos流程來獲得最新的數據。其Fast Write優化是如果當前這輪paxos寫成功,將自動獲得下一輪paxos寫的prepapre的權利,這樣下輪寫直接accept。這樣實現的好處是多點可寫,不需要一個delicated的leader,服務實現完全的高可用。當然缺點也是很明顯的,當存在寫沖突時就會大量重試導致沖突進一步加劇,甚至“雪崩”,因此Megastore論文中也提到限制單個Entity Group的寫頻率來降低沖突。

Google后來的Spanner系統重新了設計Paxos的工程實現,采用了“long-lived Paxos Leader”,所有的寫都從Leader發起,保證順序apply。這樣大大降低latency,提高系統throughput。

再換個角度想想Leader的作用,第一點,leader必須要有全局視角,擁有最新的信息;第二點,將所有的寫請求串行化,避免了沖突。對照現實生活中,leader就像沒有紅綠燈時十字路口的交警,沒有交警維護交通秩序,交通會非常擁擠。

4 總結

總體來說,Paxos是一個經典的一致性協議,目前已經成為分布式系統的實現高可用強一致的標配,由于其實現的復雜性,工程應用中層出不窮出現Paxos的各種變種和優化,包括Raft其也是paxos的一種簡化實現。Leader or not Leader這只是工程實現上的選擇,不影響正確性,各自有優缺點,但可以說Leader base的實現還是目前工程實踐中的大多數系統的選擇以及未來的方向。

Reference:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Paxos是什么 Paxos算法是基于消息傳遞且具有高度容錯特性的一致性算法,是目前公認的解決分布式一致性問題最有...
    jiangmo閱讀 1,550評論 0 6
  • 此文知識來自于:《從Paxos到Zookeeper分布式一致性原理與實踐》第二章分布式入門基礎知識,由于博主對其理...
    李文文丶閱讀 1,982評論 0 0
  • 持續更新 如何淺顯易懂地解說 Paxos 的算法? 參考資料 #8:知行學社的分布式系統與Paxos算法視頻課程,...
    xiewen閱讀 16,807評論 0 44
  • 原文:Paxos Made Simple作者:Leslie Lamport時間:01 Nov 2001 1 Int...
    隨安居士閱讀 1,597評論 1 2
  • 生命的存在和消失,在我看來是一件非常奇妙的事情。 作為一個正在接受大學教育的人,理智告訴我,你應該是一個無神論者,...
    我是安迪閱讀 440評論 2 7