Paxos算法——科普貼(下篇,設計之美)

接上篇:Paxos算法——科普貼(上篇,共識問題+故障是常態)

Paxos算法由圖靈獎得主Leslie Lamport在《The Part-Time Parliament》一文中提出(中文譯文見鏈接)。本文主要對Paxos算法步驟以及設計思路進行分析。

首先,需要明白Paxos算法適用於哪種環境(適用環境)以及Paxos算法設計目標,即:Paxos算法致力於提供什麼樣的性能(算法保證)

適用環境:非拜占庭故障下的異步系統

異步系統中,沒有時間的限制。時鐘以任意速度運行,網絡通信所需時間不確定,節點執行操作可以花費任意長的時間。 

非拜占庭故障是指,節點故障表現爲對收到的消息無法進行響應,永遠保持在當前狀態;節點之間的消息傳遞是可靠的,即:消息可以不按順序到達,可以重複發送,但不會損壞。

Paxos算法可以容忍非拜占庭故障,對於拜占庭故障,並不能很優雅地處理。

算法保證

1. Paxos算法在任何情況下均可保證安全性(Safety)

這裏安全性由兩個部分組成:

(1)非平凡性(Nontriviality):只有客戶端提出的請求才能被學習;

(2)一致性(Consistency): 同一個實例,最多隻有一個客戶端請求能被學習。 

這裏,如果節點持久存儲了客戶端請求,我們稱節點“學習”了客戶端請求。

Paxos算法中,存在一個預先確定的編號1,2,...,n,對於收到的客戶端請求,分配一個特定的編號,由<編號,客戶端請求>構成的二元組稱爲實例。Paxos通過確保每個節點收到相同的實例,節點按實例編號執行客戶端請求,即可實現共識。

2. Paxos 在少數節點故障的情況下,可以提供進展保證(Progress guarantee)

即: 如果足夠多的節點沒有故障,並且消息在超時之前到達,對於特定編號的實例,最終可以確定對應的客戶端請求,並在所有無故障節點上持久存儲該實例。

Paxos算法在異步系統中,放寬了一點要求:少數節點故障,消息最終可以送達,並沒有違背FLP定理(FLP定理不存在少數節點故障,消息最終可以送達這一限制)

下面,針對Paxos算法提供的算法保證,考慮Paxos的適用環境,對Paxos算法步驟進行介紹。

算法步驟

爲了實現安全性保證,Paxos算法需滿足非平凡性以及一致性。對於非平凡性,不難滿足,Paxos只處理客戶端提出的請求即可。對於一致性,是實現的難點。Paxos算法首先證明,如果滿足特定約束,算法即可提供一致性和進展保證。

1.相關概念

cf:學習,確認

Paxos算法中,節點持久存儲客戶端請求的過程,我們稱爲“學習”

節點首次收到特定實例(包含<編號,客戶端請求>)會進行“確認”,這裏的確認並未持久存儲,而是節點會記錄下,收到過這一實例。Paxos算法中,在“學習”客戶端請求之前,肯定會經過節點“確認”的過程。

2.特定約束

約束1:每次投票都有一個獨一無二的投票編號

約束2:任意兩次投票的法定人數的交集不爲空,即:任意兩次投票的法定人數至少有一個共同的節點。

約束3:對每次投票,如果法定人數中的節點在早期的投票中對某些實例編號(k1,k2,...,kn)的客戶端請求進行了確認,並且這次投票依然需要確定這些實例編號(k1,k2,...,kn)的客戶端請求,那麼這些實例編號(k1,k2,...,kn)的客戶端請求只能設置爲法定人數中的節點在早期投票中,最晚確認的那次客戶端請求。

這裏,投票可以理解爲執行一次Paxos算法。那麼約束1要求一次Paxos算法需要有一個獨一無二的編號來唯一標識。

法定人數指的是包含大多數節點(如果系統中一共有N個節點,那麼大多數節點指的是最少有\lfloorN/2\rfloor+1個節點,\lfloorN/2\rfloor表示N/2的下界)的節點集合,在Paxos算法中,法定人數需要和特定節點進行消息交流。約束2要求,任意兩次Paxos算法選擇的法定人數至少有一個共同節點。

約束3是實現一致性的關鍵所在。約束3要求,對於一個實例,如果一次投票中法定人數的節點在之前的投票中對客戶端請求進行了確認,那麼這個實例的客戶端請求必須設置爲法定人數中的節點在早期投票中,最晚確認的客戶端請求。那麼,對於一個實例,假設在一次投票(假設編號爲k)中,有一個客戶端請求被學習。在緊接着的一次投票(編號爲k+1)中,法定人數中的節點肯定至少存在一個節點在編號爲k的投票中,對該實例進行了確定(約束2導致)。那麼對於該實例,只能選擇編號爲k的投票中選擇的客戶端請求。以此類推,在之後的投票中,該實例的客戶端請求只能選擇編號爲k的投票中選擇的客戶端請求,進而實現了:同一個實例,最多隻有一個客戶端請求能被學習。 

如果大多數的節點沒有故障,那麼在滿足約束1-3的情況下,實例被學習是有可能的。

3.算法步驟

(1) 節點p選擇一個比之前所有投票都大的新的投票編號ba,將lastTried[p]設置爲ba,並給某個節點集合發送NextBallot(ba,n)消息,n表示編號小於等於n的實例均已被p學習。

(2) 節點q從p處收到NextBallot(ba,n)消息並且ba要大於q收到的所有NextBallot(ba,n)消息中的ba,q將nextBal[q]設置爲ba。如果q中存在小於等於n的實例未被學習,q會請求p發送這樣的實例;如果q中存在大於n的實例已經被學習,會通知p;如果q中存在大於n的實例的確認,但並未學習,則給p發送LastVote(ba, v)消息,v等於q之前發送過確認的大於n的實例集合,對於每個實例來說,其中的客戶端請求是最晚發送確認的客戶端請求。(如果ba\leqq收到的所有NextBallot(ba,n)消息中的ba,那麼就忽略NextBallot(ba,n)消息)

(3) 節點p如果收到請求發送實例的信息,則發送相應實例;如果收到其他節點發送的已學習實例的通知,則學習相應實例;如果從某個大多數集合Q中的每個牧師那都收到LastVote(ba, v)(ba= lastTried[p])消息,p會初始化一次新投票,投票編號爲ba,法定人數爲Q,實例集合爲d,d中客戶端請求的選擇滿足約束3。p給Q中所有牧師接着發送BeginBallot(ba, d)消息。

(4) 在節點q收到BeginBallot(ba, d)消息並且ba= nextBal[q],q對投票編號爲ba的實例進行確認,並記錄下確認的實例,並且給p發送一個Voted(ba, q)消息。(如果ba\neqnextBal[q],那麼就忽略BeginBallot(ba, d)消息)

(5) 如果p從Q(投票編號爲ba的投票中的法定人數)中的每個節點q那都收到了Voted(ba, q)消息,並且ba = lastTried[p],那麼p將d寫入分類賬中並給每個節點發送Success(d)消息。

(6) 在收到Success(d)消息之後,節點持久存儲d中的實例,即:學習d中的實例。

其中,步驟(1)(2)主要是爲約束3的執行收集一些必要信息(例如:早期投票中,節點最晚發送確認的客戶端請求);步驟(3)根據約束3爲實例選擇相應的客戶端請求;步驟(4)會對下一次投票收集約束3相關的信息產生影響,同時也會決定是否執行步驟(5)(6)。執行步驟(5)(6)表明實例被成功“學習”。

綜上,Paxos算法步驟可以滿足約束1-3,Paxos可以保證安全性,此時影響進展保證的因素是:如果不斷有節點嘗試進行步驟(1),投票編號ba的值設置地越來越大,那麼會阻礙下面步驟的執行(ba\leqq以及ba\neqnextBal[q]的情況發生)。因此,爲了提供進展保證,Paxos需要選出一個特定的節點(領導者),只有該節點有權執行步驟(1),(3),客戶端提出的請求也只發送給該節點。具體領導者的選擇方法,Paxos算法中並未詳細描述。


Paxos算法設計精細巧妙,本身較爲難懂,本文對Paxos算法進行了一個簡單的描述,可能存在描述不清楚的地方,歡迎進行提問。

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