Paxos算法簡介

本介紹是 Paxos Made Simple 的中文說明。會摘錄一些原來的段落講解。如果大家發現有問題的地方,參照原文。說明中部分內容摘自維基百科。
Paxos Made Simple 是因爲最初的論文比較難懂,作者又寫了這篇比較形象好懂的介紹。首先要明確的是 Paxos 算法,是爲了解決分佈式環境下一致性的問題而提出的算法。這裏將犧牲一些嚴格性,採用比較好懂的具體例子對文章加以解讀。

注意:對這個說明進行理解的時候要先理解這個過程方法:目的是在分佈式環境裏解決一致性問題。那麼先提出了兩個約束。只要保證着兩個約束就保證了問題解的 正確性。但是因爲開始的約束很難實現,於是對約束進行加強(滿足了加強了的約束就一定滿足原來的約束。比如我們提的一個約束是明天的約會對象必須是個人, 然後對這個約束做了一次加強,加強成明天的約會對象必須是個女人),最終找到可以實現的一組約束。

原文提出了一個問題,如何選擇一個值。這裏形象化成一個更實際的問題,如何確定一把鎖的歸屬。假設一個場景,一個唯一資源被一把鎖保護着,現在又很多分佈 在不同主機上的進程開始爭用這把鎖。不妨讓爭用鎖的進程分別是S1,S2,S3……。 鎖名稱L1. 那麼迴歸到原文的例子上,就是對變量L1選擇一個值,可能值爲(S1,S2,S3….). 當然,最簡單的辦法是用一個單一進程來實現,S進程向其申請鎖,誰先到歸誰。這樣的結果是,系統產生了一個單點瓶頸。那麼我們現在考慮用一個小集羣如何來 實現。這個小集羣有一些要求:其中任何一臺機器可能失效,但是這臺機器恢復回來的時候,應該是有記憶的,就是說,能找到其失效前的一些必要數據。
首先介紹兩種角色,提案者和批准人。提案者是提出議案的,批准人進行批准。注意,本文只介紹這兩者之間的交互關係,不介紹 learners。一個進程可以身兼多種角色。
現在再假設批准人有5個,組成了一個小的集羣(A1-A5)。S系列的進程是提案者,他們希望的提案就是自己佔有鎖資源。比如S1的提案是L1 = S1。 S2的提案是 L1 = S2 …… 他們其實是同一個提案,就是對L1取值的提案。只是各個S進程提案的value不一樣。顯然,只有一個提案可以獲得通過,那麼5個批准人的集羣如何確定誰 獲得通過呢?簡單來說,少數服從多數。就是獲得超過半數批准人支持的提案獲勝。我們稱超過半數的一羣批准者爲一個多數派。因爲兩個多數派至少有一個批准者 是重疊的。所以只要我們約定,一個批准者只能批准一個提案。那麼我們就可以保證不會產生1個以上提案被批准的情況了。也就是說L1不會取得超過一個的值。 因爲要求一個提案者提出唯一提案的時候也要接受。就是說,S系列進程只有一個要求鎖資源,這當然要接受的。所以我們有要求:
P1 一個批准者必須接受他收到的第一個提案。
這產生一個問題,當幾個S進程一起要求鎖的時候,可能每個批准者批准了一個。從而無法形成多數派。即便只有兩個S進程提出鎖要求,假設我們的5人集團當掉 一個,剩下四個有兩個同意S1,有兩個同意S2,還是形不成多數派。問題還是無法解決。這種情況實際上要求一個批准者應該可以批准超過一個的提案。慢着, 如此一來,誰請求都批准那不是沒有一樣嗎?所以還要有限制。爲了方便,讓我們把每個提案者提出的提案進行編號。每個提案者的編號不同,而且編號是偏序的。 具體實現隨意。在我們的例子裏,就先用機器名加變量名S1_L1,S2_L1來作爲提案的編號。當多數派批准一個提案比如S1_L1(提案S1_L1在我 們的例子中應該是L1 = S1)的時候,值被選定,提案被通過(注意“通過”這個詞,後續中,對於經過多數派批准的生效的提案,我用“通過”這個詞)。我們允許多個提案被通過,只 要他們提案的值是一樣的。比如S1_L1被通過之後,如果機器S2提出提案S2_L1,要求把鎖給S1(S2_L1:L1=S1)那麼這個提案應該也被通 過。當然我們的例子裏,S2是不會這麼幹的。那麼有下面的要求
P2 一個值爲V的提案被通過了,那麼編號比這個提案大的提案通過的條件是提案的值是V。
因爲一個提案被通過,那麼至少要被一個批准者批准。所以我們可以對P2做加強。
p2a 一個值爲V的提案被通過了,那麼編號比這個提案大的提案被批准的條件是提案的值是V。
請注意p2和p2a的區別,別糊塗了。
注意,這裏又有一個問題,假設S1_L1提案被A1,A2,A3批准,從而獲得了通過。現在S2提出提案S2_L2,提給了A5.A5跟據P1的要求,應該批准該提案,但是這是違反p2a的。所以我們需要對p2a繼續加強
p2b 一個值爲V的提案被通過了,那麼編號比這個提案大的提案的值應該是V。
只有被提出的提案纔可能被批准,我們規定了提出的提案的值應該是V,自然保證了被批准以及被通過的值。所以P2b蘊含了p2a和p2.那我們的例子來說,一旦L1的值被確定了,後續的提案只能同意。
p2b 難以實現。這裏我們引入另一個約束
p2c 提出一個編號爲n具有值v的提案的前提是:存在一個多數派,要麼他們中沒有人批准過編號小於n的任何提案,要麼他們批准的提案中編號小於n的最大的提案值是v。
下面通過數學歸納法證明p2c蘊含了p2b:
假設具有值 v 的提案 m 獲得通過,當 n=m+1 時,根據 P2c,由於任何一個多數派中至少有一個批准了 m,因此提案n具有值 v;若 (m+1)..(n-1) 所有提案都具有值v,根據 P2c,若反設新提案 n 不具有值v 則存在一個多數派,他們沒有批准過 m..(n-1) 中的任何提案。但是我們知道,他們中至少有一個人批准了 m。於是我們導出了矛盾,獲得了證明。也就是說,只要滿足p2c,那麼p2b就得到滿足。
以上這麼囉嗦的一堆,其實是證明了,只要保證了p2c,我們就能保證選出唯一值。那麼下面看如何設計算法保證p2c。
保證p2c的關鍵問題,其實是要批准者做出不批准某種類型提案的承諾。所以:提案者提出一個提案前,首先要和足以形成多數派的批准者進行通信,獲得他們進 行的最近一次批准活動的編號,並且得到他們不批准比當前提案編號小的提案的承諾(prepare 過程),之後根據回收的信息決定這次提案的 value,形成提案開始投票。當獲得多數批准者批准後,提案獲得通過。這個簡略的過程經過進一步細化後就形成了 Paxos 算法。

如果一個批准者在 prepare 過程中回答了一個編號爲n的提案,但是在開始對 n 進行投票前,又批准另一個提案編號小於n的提案,如果兩個提案具有不同的 value,這個批准就會違背 P2c。因此在 prepare 過程中,批准者對於不會再批准編號小於 n 的提案的承諾是保證算法正確的基礎。所以又有一個對 P1 的加強:
P1a:當且僅當批准者沒有收到編號大於 n 的提案請求時,批准者批准編號爲 n 的提案。

現在已經可以提出完整的算法了。

通過一個決議分爲兩個階段:

1. prepare 階段:
1. 提案者選擇一個提案編號 n 並將 prepare 請求發送給批准者中的一個多數派;
2. 批准者收到 prepare 消息後,如果提案的編號大於它已經回覆的所有 prepare 消息,則批准者將自己上次的批准回覆給提案者,並承諾不再批准小於 n 的提案;
2. 批准階段:
1. 當一個提案者收到了多數批准者對 prepare 的回覆後,就進入批准階段。它要向回覆 prepare 請求的批准者發送批准的請求,包括編號 n 和根據 P2c 決定的 value(如果根據 P2c 沒有決定 value,那麼它可以自由決定 value)。
2. 在不違背自己向其他提案者的承諾的前提下,批准者收到批准請求後即批准這個請求。

這個過程在任何時候中斷都可以保證正確性。

這個算法的正確性和完備性就是上面的證明。但是爲了便於理解,我們可以用我們上面的例子來描述一個決議過程。這個描述僅僅是便於大家理解。描述中有一些在實際算法上不合適的地方,這裏不考慮。

批准者是A1-A5.申請者是S系列。提案是決定L1的取值。

首先S2提出編號是0001S2的提案內容是L1=S2.我們採用 提案者:編號[值]這種記錄方式記做 S2:0001S2[S2]。它要先進行prepare階段,於是向A1,A2,A3,A4發送了請求。

同時S1提出S1:0001S1[S1],發給A1-A5.進行prepare。

我們來看這5個A的回覆:我們用 批准者[收到的提案:給出的回覆]這個格式來描述一下A系列的行爲。回覆有三種1 ok表示做出承諾(沒有做出批准的時候)2 null表示沒有給回覆(提案編號比承諾過的編號小)3value表示做出承諾,同時給出value(已經做出過批准的時候)

A1[0001S1:ok] [0001S2:ok] A1先接到s1的prepare請求,做出了承諾,又接到s2的請求,做出了承諾 現在A1的承諾是不批准<0001S2 A1要記住他的承諾和值 記做 A1-(0001S2,null)

A3[0001S2:ok] [0001S1:null] A3-(0001S2,null)

A2[0001S1:ok] A2-(0001S1,null)

A5[0001S1:ok] A5-(0001S1,null)

注意,到此時,S1已經收到了一個多數派的回覆(A1,A2,A5) A3因爲違反承諾,沒有給S1回覆。這時S1開始批准階段的請求,其中提案的值是S1(因爲prepare階段沒有批准者返回值)。請求順序是 A5,A4,A3,A2,A1(A3雖然沒有給回覆,但是是可以向它發批准請求的。算法優化的問題現在不討論,只講正確性)。那麼這個時候的回覆應該是什 麼樣呢?

A5[0001S1:ok] A5要記住當前的提案編號是0001S1 value是S1。記做 A5-(0001S1,S1)

A4 我們假設A4由於網絡原因,沒有收到prepare階段的請求,直接受到了批准階段請求。按照規則,他應該做出批准,並且記住狀態

A4[0001S1:ok] A4-(0001S1,S1)

A3 已經做出承諾不能批准所以不回覆

A3[0001S1:null] A3-(0001S2,null)

A2[0001S1:ok] A2-(0001S1,S1)

已經達到多數派,提案通過,A1其實不會給出回覆。不過沒關係了。現在我們再看後來的提議者S2. S2向A1,A2,A3,A4發出請求,到目前爲止,只有A1,A3收到了請求。我們繼續推演後續的A收到請求的反應。

假設現在A4收到請求 考慮A4的狀態A4-(0001S1,S1) 因爲新的提議編號更大,所以A4要回復給S2提議的值,狀態不變

A4[0001S2:S1] A4-(0001S1,S1)

A2[0001S2:S1] A2-(0001S1,S1)

這個時候S2妄圖提出值爲S2的提案的企圖沒能得到多數派的同意,不會進入批准階段了。

————————————————————————–

這個例子只是形象的看了一下算法是如何工作的。實際算法的正確性和完備性是上面的證明過程。這種舉例只是爲了幫助形象化理解,有興趣的同學可以自己再推演 一下其他情況,比如S2勝出,比如S1在得到多數派prepare ok後 只向兩個A發出了批准請求然後掛掉等情況。

真正在做算法實現的時候還是有一些注意的事情的,比如我們假設一個比價極端的情況,S1在prepare時候向A1-A5發申請,都得到了回覆。然後S2 也發了一遍申請,當然也都得到回覆,這個時候S1發出提案,實際上是得不到回覆的。現在假設S2突然掛掉。那麼對於我們的例子,沒人得到鎖。如果是用來選 master,到現在還沒人是master。這個時候S1應該再做一次提案採用更大的一個編號(這就是爲什麼我的例子中,提案編號前面是幾位的序號)。但 是這樣實現,又面臨着S1,S2交替增大編號,誰也得不到批准的問題。這些問題都是需要注意的(實現的時候足夠注意就可以解決)。這些不屬於本文討論內 容,這裏只是提醒一下。

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
閱讀(1178) | 評論(1) | 轉發(0) |
給主人留下些什麼吧!~~
00_avatar_small.jpg

chinaunix網友2009-10-13 16:30:04

說的很好,不過有點不繫統,例子也不是很詳細。 還是鼓勵一下。。。

評論熱議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章