共識 | 拜占庭容錯的表明 PBFT

共識 | 拜占庭容錯的表明 PBFT

本文是共識系列文章的第一篇。在共識系列文章中,我將會向你們介紹常見的共識算法。在文章開頭,我會用必定篇幅介紹一致性問題的基礎知識。一致性問題是分佈式系統中最基礎也是最重要的問題,而共識算法就是用來解決分佈式系統一致性的。以後,我會介紹一個很是經典的拜占庭容錯算法 PBFT。git

預備

一致性

一致性(Consistency),早期也叫(Agreement),是指在分佈式系統領域中,對於多個服務節點,給定一系列操做,在約定協議的保障下,使得它們對處理結果達成「某種程度」的協同。分佈式系統達成一致的過程應知足:算法

  • 可終止性(Termination):一致的結果在有限時間內能完成;安全

  • 約同性(Agreement):不一樣節點最終完成決策的結果是相同的;網絡

  • 合法性(Validity):決策的結果必須是某個節點提出的提案。併發

共識

要保障系統不一樣程度的一致性,就須要共識算法來完成。共識算法解決的是分佈式系統對某個提案(Proposal),全部誠實節點達成一致意見的過程。那麼共識須要解決的問題能夠作以下的抽象:異步

  • 如何提出一個待共識的提案?分佈式

  • 如何讓多個節點對該提案達成共識?ide

CFT & BFT

對於分佈式系統來講,若是節點間通訊十分順暢,各個節點都能瞬間響應,那麼只須要簡單廣播投票和應答就能夠解決一致性問題。而後現實並非這樣。節點每每會遇到網絡中斷、節點故障,甚至是被非法入侵僞造消息的問題。節點遇到的問題能夠進行以下的分類:區塊鏈

  • 節點出現故障但不會僞造信息的狀況稱爲「非拜占庭錯誤」;優化

  • 節點會僞造信息惡意響應的狀況稱爲「拜占庭錯誤」,僞造信息的節點稱爲拜占庭節點。

相對應的,共識算法也能夠分爲 CFT 和 BFT 兩類:

  • CFT(Crash Fault Tolerance):只容忍節點故障,不容忍節點做惡;

  • BFT(Byzantine Fault Tolerance):容忍節點故障與做惡。

 

FLP 不可能原理

計算機科學家證實了:在網絡可靠,但容許節點失效的最小化異步系統中,不存在一個能夠解決一致性問題的肯定性共識算法。這彷佛意味着去設計一個共識算法是徒勞的,然而科學告訴你什麼是不可能的;工程則告訴你,付出一些代價,能夠把它變成可行。也就是說在付出多大的代價的狀況下,可以達到共識。

兩軍問題

白軍駐紮在溝渠裏,藍軍和紅軍分別駐紮在溝渠兩邊。白軍比藍軍和紅軍中任何一支軍隊都更爲強大,可是藍軍和紅軍若能同時協力進攻則可以戰勝白軍。藍軍和紅軍不可以越過溝渠遠程地溝通,只能派遣通訊兵穿過溝渠去通知對方協商進攻時間。可是通訊兵可能會迷路或者被敵軍截獲,消息被篡改。

 

根據 FLP 不可能原理,這個問題無通用解,然而這一問題在通訊領域又必須解決。基於成本可控的考慮,如今使用 TCP 協議的三次握手來(不完全的)解決這一問題。

拜占庭將軍問題

一組拜占庭將軍分別各率領一支軍隊共同圍困一座城市。爲了簡化問題,將各支軍隊的行動策略限定爲進攻或撤離兩種。由於部分軍隊進攻部分軍隊撤離可能會形成災難性後果,所以各位將軍必須經過投票來達成一致策略,即全部軍隊一塊兒進攻或全部軍隊一塊兒撤離。由於各位將軍分處城市不一樣方向,他們只能經過信使互相聯繫。在投票過程當中每位將軍都將本身投票給進攻仍是撤退的信息經過信使分別通知其餘全部將軍,這樣一來每位將軍根據本身的投票和其餘全部將軍送來的信息就能夠知道共同的投票結果而決定行動策略。

上述的故事映射到分佈式系統裏,將軍便成了共識節點,叛徒就是拜占庭節點。與兩軍問題不一樣的是,拜占庭將軍問題中並不去考慮通訊兵是否會被截獲或沒法傳達信息等問題,也就是說在假定信道沒有問題的狀況下去討論一致性與容錯性。

有了這些預備知識能夠更好的理解共識算法。下面咱們進入今天的正題——PBFT。

PBFT 共識算法

PBFT 是 Practical Byzantine Fault Tolerance 的縮寫,意爲實用拜占庭容錯算法。該算法首次將拜占庭容錯算法複雜度從指數級下降到了多項式級,其能夠在惡意節點不高於總數 1/3 的狀況下同時保證安全性(Safety)和活性(Liveness)。咱們假設全部節點的總數爲 R ,拜占庭節點數量爲 f,下面給出安全性證實:

設想 f 個叛變者和 k 個忠誠者,叛變者故意使壞,能夠給出錯誤的結果,也能夠不響應。某個時候 F 個叛變者都不響應,則 k 個忠誠者取多數既能獲得正確結果。當 f 個叛變者都給出一個惡意的提案,而且 k 個忠誠者中有 f 個離線時,剩下的 k - f 個忠誠者此時沒法分別是否混入了叛變者,仍然要確保取多數能獲得正確結果,所以,k - f > f,即 k > 2f 或 R - f > 2f,因此係統總體規模 R 要大於 3f。因此爲了能確保達成共識的拜占庭系統節點數至少爲 4,此時最多容許出現 1 個拜占庭節點。

PBFT 是一種基於狀態機副本複製的算法,每一個狀態機的副本都保存了服務的狀態,同時也實現了服務的操做。PBFT 中全部的副本都在視圖(View)的輪換過程當中運做,當主節點掉線的時候就啓動視圖更換過程保證算法的持續運行。

從上面的流程圖能夠看出,PBFT 算法的流程以下:

  1. 客戶端向主節點發送請求;

  2. 主節點向其餘副本廣播請求;

  3. 全部副本執行請求後,將結果返回給客戶端;

  4. 客戶端須要等待 2f+1 個不一樣副本返回相同的結果,做爲最終結果。

這裏面暗含着的是全部節點都是肯定性的和全部節點都從相同的狀態開始執行這兩個條件。

首先客戶端發送了一個請求到主節點,以後經典的三階段協議(three-phase protocol)就拉開了序幕。

預準備階段

首先,主節點向全部副本節點發送預準備消息。這裏麪包含有消息序號,視圖編號和消息的摘要。須要注意的是預準備消息是不包含請求的,這樣作有兩個好處,一是壓縮消息大小提高傳播效率,二是將請求排序與請求傳輸解耦。

接着副本節點會去驗證消息的簽名是否正確,視圖編號是否一致和消息序號是否知足水線要求。這裏就要引出 PBFT 中的水線機制(watermark)。對於消息的序號 n,要求其在水線 h 和 H 之間。水線存在的意義在於防止一個失效節點使用一個很大的序號消耗序號空間。

準備階段

若是副本節點接受預準備消息,就進入了準備階段。在準備階段,每個節點都向其餘節點發送包含本身 ID 的準備消息,同時也接收其餘節點的準備消息。對於收到準備消息一樣進行合法性檢查。驗證經過則把這個準備消息寫入本身的消息日誌中。一個節點集齊至少 2f+1 個驗證過的消息才進入準備狀態。

提交階段

在提交階段,每一個節點廣播 commit 消息告訴其餘節點本身已經進入準備狀態。若是集齊至少 2f+1 的 commit 消息則說明提案經過。

在通過了三階段協議以後,每一個副本節點都想客戶端發送回覆,副本節點會把時間戳比已回覆時間戳更小的請求丟棄,以保證請求只會被執行一次。

總結

PBFT 共識算法在 1999 年的時候由 Castro 和 Liskov 正式提出,它在設計時考慮的共識對象是一些相對不大的消息。爲了對消息進行排序,PBFT 設計了水線機制,經過 checkpoint 機制移動水線,用以併發地處理多個消息的投票過程。同時, PBFT 只有當某個節點做惡或掉線才觸發視圖的切換,主節點的更換。這是由於視圖的切換過程也是須要共識的,這一過程很是耗時,所以 PBFT 不能接受頻繁的視圖變動。再加上爲了配合水位機制,視圖切換的消息都相對普通消息要大得多。由於以上緣由,PBFT 的設計很是複雜,效率不高。

然而,隨着技術的發展,區塊鏈技術的誕生輕鬆的化解掉了 PBFT 在設計上的一些問題。 在區塊鏈中,每個消息(區塊)先後相繼,用於併發處理的水位機制毫無用處,所以水線機制以及爲此服務的 checkpoint 機制就沒有存在的意義了。沒有了水線機制和 checkpoint,阻礙視圖切換的就只剩下視圖切換的共識過程了,而這一點又被區塊鏈自己做爲共識帳本的特色給簡化掉了。若是節點的切換經過鏈上的數據來達成共識,那麼本來須要通過在線共識的過程又省掉了。

所以大量的區塊鏈項目都使用了改進的 PBFT 用做共識算法,做爲拜占庭容錯的表明的 PBFT 也在不斷地優化的過程當中煥發出了新的生機。

 

ref:

1.區塊鏈技術指南 :https://legacy.gitbook.com/book/yeasy/blockchain_guide/details

2.Castro M, Liskov B. Practical Byzantine fault tolerance[C]//OSDI. 1999, 99: 173-186.

相關文章
相關標籤/搜索