分佈式理論之一:Paxos算法的通俗理解

分佈式理論之一:Paxos算法的通俗理解程序員

維基的簡介:Paxos算法是萊斯利·蘭伯特(Leslie Lamport,就是 LaTeX 中的"La",此人如今在微軟研究院)於1990年提出的一種基於消息傳遞且具備高度容錯特性的一致性算法。算法

Paxos算法目前在Google的Chubby、MegaStore、Spanner等系統中獲得了應用,Hadoop中的ZooKeeper也使用了Paxos算法,在上面的各個系統中,使用的算法與Lamport提出的原始Paxos並不徹底同樣,這個之後再慢慢分析。本博文的目的是,如何讓一個小白在半個小時以內理解Paxos算法的思想。小白可能對數學不感興趣,對分佈式的複雜理論不熟悉,只是一個入門級程序員。之因此想寫這篇博文,是由於本身看了網上不少介紹Paxos算法的文章,以及博客,包括Lamport的論文,感受仍是難以理解,大多過於複雜,本人一直認爲,複雜高深的理論背後必定基於一些通用的規律,而這些通用的規律在生活中其實咱們早就遇到過,甚至用過。因此,咱們先忽略Paxos算法自己,從生活中的小事開始談起。數據庫

假若有一羣驢友要決定中秋節去旅遊,這羣驢友分佈在全國各地,假定一共25我的,分別在不一樣的省,要決定到底去拉薩、昆明、三亞等等哪一個地點(會合時間中秋節已經定了,此時須要決定旅遊地)。最直接的方式固然就是建一個QQ羣,你們都在裏面投票,按照少數服從多數的原則。這種方式相似於「共享內存」實現的一致性,實現起來簡單,但Paxos算法不是這種場景,由於Paxos算法認爲這種方式有一個很大的問題,就是QQ服務器掛掉怎麼辦?Paxos的原則是容錯性必定要很強。因此,Paxos的場景相似於這25我的相互之間只能發短信,須要解決的核心問題是,哪怕任意的一部分人(Paxos的目的實際上是少於半數的人)「失聯」了,其它人也可以在會合地點上達成一致。好了,怎麼設計呢?服務器

這25我的找了另外的5我的(固然這5我的能夠從25我的中選,這裏爲了描述方便,就單拿出另外5我的),好比北京、上海、廣州、深圳、成都的5我的,25我的都給他們發短信,告訴本身傾向的旅遊地。這5我的相互之間能夠並不通訊,只接受25我的發過來的短信。這25我的咱們稱爲驢友,那5我的稱爲隊長。併發

先來看驢友的邏輯。驢友能夠給任意5個隊長都發短信,發短信的過程分爲兩個步驟:分佈式

第一步(申請階段):詢問5個隊長,試圖與隊長溝通旅遊地。由於每一個隊長一直會收到不一樣驢友的短信,不能跟多個驢友一塊兒溝通,在任什麼時候刻只能跟一個驢友溝通,按照什麼原則才能作到公平公正公開呢?這些短信都帶有發送時間,隊長採用的原則是贊成與短信發送時間最新的驢友溝通,若是出現了更新的短信,則與短信更新的驢友溝通。總之,做爲一個有話語權的人,只有時刻保持傾聽最新的呼聲,才能作出最明智的選擇。在驢友發出短信後,等着隊長回覆。某些隊長可能會回覆說,你這條短信太老了,我不與你溝通;有些隊長則可能返回說,你的短信是我收到的最新的,我贊成跟你溝通。對於後面這些隊長,還得返回本身決定的旅遊地。關於隊長是怎麼決定旅遊地的,後面再說。oop

對於驢友來講,第一步必須至少有半數以上隊長都贊成溝通了,才能進入下一步。不然,你連溝通的資格都沒有,一直在那兒狂發吧。你發的短信更新,你得到溝通權的可能性才更大。。。。。。性能

由於至少有半數以上隊長(也就是3個隊長以上)贊成,你才能與隊長們進行實質性的溝通,也就是進入第二步;而隊長在任什麼時候候只能跟1個驢友溝通,因此,在任什麼時候候,不可能出現兩個驢友都達到了這個狀態。。。固然,你能夠經過狂發短信把溝通權搶了。。。。設計

對於得到溝通權的那個驢友(稱爲A),那些隊長會給他發送他們本身決定的旅遊地(也可能都尚未決定)。能夠看出,各個隊長是本身決定旅遊地的,隊長之間無需溝通。事務

第二步(溝通階段):這個幸運的驢友收到了隊長們給他發的旅遊地,可能有幾種狀況:

第一種狀況:跟A溝通的隊長們(不必定是所有5個隊長,可是半數以上)所有都尚未決定到底去那兒旅遊,此時驢友A心花盛開,給這些隊長髮第二條短信,告訴他們本身但願的旅遊地(好比馬爾代夫);

可能會收到兩種結果:一是半數以上隊長都贊成了,因而代表A建議的馬爾代夫被半數以上隊長都贊成了,整個決定過程完畢了,其它驢友早晚會知道這個消息的,A先去收拾東西準備去馬爾代夫;除此以外,代表失敗。可能隊長出故障了,好比某個隊長在跟女友打電話等等,也可能被其它驢友搶佔溝通權了(由於隊長喜新厭舊嘛,只有要更新的驢友給本身發短信,本身就與新人溝通,A的建議隊長不一樣意)等等。無論怎麼說,苦逼的A還得從新從第一步開始,從新給隊長們發短信申請。

第二種狀況:至少有一個隊長已經決定旅遊地了,A可能會收到來自不一樣隊長決定的多個旅遊地,這些旅遊地是不一樣隊長跟不一樣驢友在不一樣時間上作出的決定,那麼,A會先看一下,是否是有的旅遊地已經被半數以上隊長贊成了(好比3個隊長都贊成去三亞,1個贊成去昆明,另一個沒搭理A),若是出現了這種狀況,那就別扯了,說明整個決定過程已經達成一致了,收拾收拾準備去三亞吧,結束了;若是都沒有達到半數以上(好比1個贊成去昆明,1個贊成去三亞,2個贊成去拉薩,1個沒搭理我),A做爲一個高素質驢友,也不按照本身的意願亂來了(Paxos的關鍵所在,後者認同前者,不然整個決定過程永無止境),雖然本身原來可能想去馬爾代夫等等。就給隊長們發第二條短信的時候,告訴他們本身但願的旅遊地,就是本身收到的那堆旅遊地中最新決定的那個。(好比,去昆明那個是北京那個隊長前1分鐘決定的,去三亞的決定是上海那個隊長1個小時以前作出來的,因而頂昆明)。驢友A的想法是,既然有隊長已經作決定了,那我就乾脆頂最新那個決定。

從上面的邏輯能夠看出,一旦某個時刻有半數以上隊長贊成了某個地點好比昆明,緊跟着後面的驢友B繼續發短信時,若是得到溝通權,由於半數以上隊長都贊成與B溝通了,說明B收到了來自半數以上隊長髮過來的消息,B必然會收到至少一個隊長給他發的昆明這個結果(不然說明半數以上隊長都沒有贊成昆明這個結果,這顯然與前面的假設矛盾),B因而會頂這個最新地點,不會更改,由於後面的驢友都會頂昆明,所以贊成昆明的隊長愈來愈多,最終必然達成一致。

看完了驢友的邏輯,那麼隊長的邏輯是什麼呢?

隊長的邏輯比較簡單。

在申請階段,隊長只會選擇與最新發申請短信的驢友溝通,隊長知道本身接收到最新短信的時間,對於更老的短信,隊長不會搭理;隊長贊成溝通了的話,會把本身決定的旅遊地(或者還沒決定這一信息)發給驢友。

在溝通階段,驢友C會把本身但願的旅遊地發過來(同時會附加上本身申請短信的時間,好比3分鐘前),因此隊長要檢查一下,若是這個時間(3分鐘前)確實是當前本身最新接收到申請短信的時間(說明這段時間沒有驢友要跟本身溝通),那麼,隊長就贊成驢友C的這個旅遊地了(好比昆明,哪怕本身1個小時前已經作過去三亞的決定,誰讓C更新呢,因而更新爲昆明);若是不是最新的,說明這3分鐘內又有其它驢友D跟本身申請了,由於本身是個喜新厭舊的傢伙,贊成與D溝通了,因此驢友C的決定本身不會贊成,等着D一下子要發過來的決定吧。

Paxos的基本思想大體就是上面的過程。能夠看出,其實驢友的策略纔是Paxos的關鍵。讓咱們來跟理論對應一下。

Paxos主要用於保證分佈式存儲中副本(或者狀態)的一致性。副本要保持一致,那麼,全部副本的更新序列就要保持一致。由於數據的增刪改查操做通常都存在多個客戶端併發操做,到底哪一個客戶端先作,哪一個客戶端後作,這就是更新順序。若是不是分佈式,那麼能夠利用加鎖的方法,誰先申請到鎖,誰就先操做。可是在分佈式條件下,存在多個副本,若是依賴申請鎖+副本同步更新完畢再釋放鎖,那麼須要有分配鎖的這麼一個節點(若是是多個鎖分配節點,那麼又出現分佈式鎖管理的需求,把鎖給哪個客戶端又成爲一個難點),這個節點又成爲單點,豈不是可靠性不行了,失去了分佈式多副本的意義,同時性能也不好,另外,還會出現死鎖等狀況。

因此,說來講去,只有解決分佈式條件下的一致性問題,彷佛才能解決本質問題。

如上面的例子,Paxos解決這一問題利用的是選舉,少數服從多數的思想,只要2N+1個節點中,有N個以上贊成了某個決定,則認爲系統達到了一致,而且按照Paxos原則,最終理論上也達到了一致,不會再改變。這樣的話,客戶端沒必要與全部服務器通訊,選擇與大部分通訊便可;也無需服務器都所有處於工做狀態,有一些服務器掛掉,只有保證半數以上存活着,整個過程也能持續下去,容錯性至關好。所以,之前看有的博客說在部署ZooKeeper這種服務的時候,須要奇數臺機器,這種說法固然有必定來源背景,好比若是是5臺,那麼任意客戶端與任意其中3臺達成一致就至關於投票結束,不過6臺有何不可?只是此時須要與4臺以上達成一致。

Paxos中的Acceptor就至關於上面的隊長,Proposer就至關於上面的驢友,epoch編號就至關於例子中申請短信的發送時間。關於Paxos的正式描述已經不少了,這裏就不復述了,關於Paxos正確性的證實,由於比較複雜,之後有時間再分析。另外,Paxos最消耗時間的地方就在於須要半數以上贊成溝通了才能進入第二步,試想一下,一開始,全部驢友就給隊長狂發短信,每一個隊長收到的最新短信的是不一樣驢友,這樣,就難以達到半數以上都贊成與某個驢友溝通的狀態,爲了減少這個時間,Paxos還有Fast Paxos的改進等等,有空再分析。

卻是有一些問題能夠思考一下:在Paxos以前,或者說除了Chubby,ZooKeeper這些系統,其它分佈式系統一樣面臨這樣的一致性問題,好比HDFS、分佈式數據庫、Amazon的Dynamo等等,解決思路又不一樣,有空再進行對比分析。

最後談談一致性這個名詞。

關於Paxos說的一致性,我的理解是指冗餘副本(或狀態等,但都是由於存在冗餘)的一致性。這與關係型數據庫中ACID的一致性說的不是一個東西。在關係數據庫裏,能夠連副本都沒有,何談副本的一致性?按照經典定義,ACID中的C指的是在一個事務中,事務執行的結果必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。那麼,什麼又是一致性狀態呢,這跟業務約束有關係,好比經典的轉帳事務,事務處理完畢後,不能出現一個帳戶錢被扣了,另外一個帳戶的錢沒有增長的狀況,若是二者加起來的錢仍是等於轉帳前的錢,那麼就是一致性狀態。

從不少博文來看,對這兩種一致性每每混淆起來。另外,CAP原則裏面所說的一致性,我的認爲是指副本一致性,與Paxos裏面的一致性接近。都是處理「由於冗餘數據的存在而須要保證多個副本保持一致」的問題,NoSQL放棄的強一致性也是指副本一致性,最終一致性也是指副本達到徹底相同存在必定延時。

固然,若是數據庫自己是分佈式的,且存在冗餘副本,則除了解決事務在業務邏輯上的一致性問題外,同時須要解決副本一致性問題,此時能夠利用Paxos協議。但解決了副本一致性問題,還不能徹底解決業務邏輯一致性;若是是分佈式數據庫,但並不存在副本的狀況,事務的一致性須要根據業務約束進行設計。

另外,談到Paxos時,還會涉及到拜占庭將軍問題,它指的是在存在消息丟失的不可靠信道上試圖經過消息傳遞的方式達到一致性是不可能的。Paxos自己就是利用消息傳遞方式解決一致性問題的,因此它的假定是信道必須可靠,這裏的可靠,主要指消息不會被篡改。消息丟失是容許的。

關於一致性、事務的ACID,CAP,NoSQL等等問題,之後再詳細分析。本文的描述也許可能存在一些舉例不太恰當的地方,若是錯誤,歡迎批評指正。

相關文章
相關標籤/搜索