古詩詞大全網 - 藝術簽名 - [轉載] 分布式系統核心問題--拜占庭問題與算法

[轉載] 分布式系統核心問題--拜占庭問題與算法

拜占庭問題(Byzantine Problem)更為廣泛,討論的是允許存在少數節點作惡(消息可能被偽造)場景下的壹致性達成問題。拜占庭容錯(Byzantine Fault Tolerant,BFT)算法討論的是在拜占庭情況下對系統如何達成***識。

在拜占庭將軍問題之前,就已經存在兩將軍問題(Two Generals Paradox):兩個將軍要通過信使來達成進攻還是撤退的約定,但信使可能迷路或被敵軍阻攔(消息丟失或偽造),如何達成壹致?根據FLP不可能原理,這個問題無通用解。

拜占庭問題又叫拜占庭將軍問題(Byzantine Generals Problem),是Leslie Lamport等科學家於1982年提出用來解釋壹致性問題的壹個虛構模型。拜占庭是古代東羅馬帝國的首都,由於地域寬廣,守衛邊境的多個將軍(系統中的多個節點)需要通過信使來傳遞消息,達成某些壹致的決定。但由於將軍中可能存在叛徒(系統中節點出錯),這些叛徒將努力向不同的將軍發送不同的消息,試圖幹擾***識的達成。拜占庭問題即為在此情況下,如何讓忠誠的將軍們能達成行動的壹致。

論文中指出,對於拜占庭問題來說,假如節點總數為N,叛變將軍數為F,則當N≥3F+1時,問題才有解,由BFT算法進行保證。

例如,N=3,F=1時。

提案人不是叛變者,提案人發送壹個提案出來,叛變者可以宣稱收到的是相反的命令。則對於第三個人(忠誠者)收到兩個相反的消息,無法判斷誰是叛變者,則系統無法達到壹致。

提案人是叛變者,發送兩個相反的提案分別給另外兩人,另外兩人都收到兩個相反的消息,無法判斷究竟誰是叛變者,則系統無法達到壹致。

更壹般的,當提案人不是叛變者,提案人提出提案信息1,則對於合作者來看,系統中會有N-F份確定的信息1,和F份不確定的信息(可能為0或1,假設叛變者會盡量幹擾壹致的達成),N-F>F,即N>2F情況下才能達成壹致。

當提案人是叛變者,會盡量發送相反的提案給N-F個合作者,從收到1的合作者看來,系統中會存在(N-F)/2個信息1,以及(N-F)/2個信息0;從收到0的合作者看來,系統中會存在(N-F)/2個信息0,以及(N-F)/2個信息1;另外存在F-1個不確定的信息。合作者要想達成壹致,必須進壹步對所獲得的消息進行判定,詢問其他人某個被懷疑對象的消息值,並通過取多數來作為被懷疑者的信息值。這個過程可以進壹步遞歸下去。

Leslie Lamport等人在論文《Reaching agreement in the presence of faults》中證明,當叛變者不超過1/3時,存在有效的拜占庭容錯算法(最壞需要F+1輪交互)。反之,如果叛變者過多,超過1/3,則無法保證壹定能達到壹致結果。

那麽,當存在多於1/3的叛變者時,有沒有可能存在解決方案呢?

設想F個叛變者和L個忠誠者,叛變者故意使壞,可以給出錯誤的結果,也可以不響應。某個時候F個叛變者都不響應,則L個忠誠者取多數即能得到正確結果。當F個叛變者都給出壹個惡意的提案,並且L個忠誠者中有F個離線時,剩下的L-F個忠誠者此時無法分別是否混入了叛變者,仍然要確保取多數能得到正確結果,因此,L-F>F,即L>2F或NF>2F,所以系統整體規模N要大於3F。

能確保達成壹致的拜占庭系統節點數至少為4,此時最多允許出現1個壞的節點。

3.拜占庭容錯算法

拜占庭容錯算法(Byzantine Fault Tolerant,BFT)是面向拜占庭問題的容錯算法,解決的是在網絡通信可靠但節點可能故障情況下如何達成***識。拜占庭容錯算法最早的討論在1980年Leslie Lamport等人發表的論文《Polynomial Algorithms for Byzantine Agreement》,之後出現了大量的改進工作。長期以來,拜占庭問題的解決方案都存在復雜度過高的問題,直到PBFT算法的提出。

1999年,Castro和Liskov於論文《Practical Byzantine Fault Tolerance and Proactive Recovery》中提出的Practical Byzantine Fault Tolerant(PBFT)算法,基於前人工作進行了優化,首次將拜占庭容錯算法復雜度從指數級降低到了多項式級,目前已得到廣泛應用。其可以在失效節點不超過總數1/3的情況下同時保證Safety和Liveness。

PBFT算法采用密碼學相關技術(RSA簽名算法、消息驗證編碼和摘要)確保消息傳遞過程無法被篡改和破壞。

算法的基本過程如下:

·首先通過輪換或隨機算法選出某個節點為主節點,此後只要主節點不切換,則稱為壹個視圖(View);

·在某個視圖中,客戶端將請求<REQUEST,operation,timestamp,client>發送給主節點,主節點負責廣播請求到所有其他副本節點;

·所有節點處理完成請求,將處理結果<REPLY,view,timestamp,client,id_node,response>返回給客戶端。客戶端檢查是否收到了至少f+1個來自不同節點的相同結果,作為最終結果。主節點廣播過程包括三個階段的處理:預準備(pre-prepare)階段、準備(prepare)階段和提交(commit)階段。預準備和準備階段確保在同壹個視圖內請求發送的順序正

確;準備和提交階段則確保在不同視圖之間的確認請求是保序的:

·預準備階段: 主節點為從客戶端收到的請求分配提案編號,然後發出預準備消息 <<PRE-PREPARE,view,n,digest>,message>給各副本節點,其中message是客戶端的請求消息,digest是消息的摘要;

·準備階段: 副本節點收到預準備消息後,檢查消息合法,如檢查通過則向其他節點發送準備消息<PREPARE,view,n,digest,id>,帶上自己的id信息,同時接收來自其他節點的準備消息。收到準備消息的節點對消息同樣進行合法性檢查。驗證通過則把這個準備消息寫入消息日誌中。集齊至少2 f+1個驗證過的消息才進入準備狀態;

·提交階段: 廣播commit消息,告訴其他節點某個提案n在視圖v裏已經處於準備狀態。如果集齊至少2 f+1個驗證過的commit消息,則說明提案通過。

具體實現上還包括視圖切換、checkpoint機制等,可自行參考論文內容。