實用拜占庭容錯算法(PBFT)是由 Barbara Liskov 和 Miguel Castro 于 90 年代末提出的一種共識算法。原論文鏈接如下:
http://pmg.csail.mit.edu/papers/osdi99.pdf
pBFT 被設計為在異步(響應請求的時間沒有上限)系統中高效運行。它針對低開銷時間進行了優化。其目標是解決現有拜占庭容錯解決方案中存在的許多問題。應用領域包括分布式計算和區塊鏈。
PBFT在保證可用性和安全性(liveness & safety)的前提下,提供了(n-1)/3的容錯性,意思就是如果系統內有n臺機子,那么系統最多能容忍的作惡/故障節點為(n-1)/3個。(作惡節點可以不響應或者回應錯誤的信息)。
也就是說為了保證pbft算法的正確性,節點總數量n和作惡節點數量f必須滿足n > 3f,如何證明呢?
我們在設計異步通信算法的時候,我們不知道那f個節點是惡意節點還是故障節點,這f個節點可以不發送消息,也可以發送錯誤的消息,所以在設計閾值的時候,我們要保證必須在n-f個狀態復制機的溝通內,就要做出決定;而且我們并不知道,這n-f個里面有幾個是作惡節點,我們必須保證正常的節點大于作惡節點數。所以有 n-f-f > f,從而得出了n > 3f。
一、拜占庭將軍問題
Byzantine Generals' Problem 拜占庭將軍問題在 1982 年微軟研究院由 LESLEY LAMPORT、ROBERT SHOSTAK 和 MARSHALL PEASE 撰寫的論文中得到了恰當的解釋:
想象一下,拜占庭軍隊的幾個分隊在敵對城市外扎營,每個分隊由各自的將軍指揮。將軍們只能通過信使互相通信。在觀察了敵人之后,他們必須制定一個共同的行動計劃。然而,一些將軍可能是叛徒,試圖阻止忠誠的將軍們達成一致。將軍們必須決定何時進攻城市,但他們需要大部分軍隊同時進攻。忠誠的將軍們必須有一個算法來保證:
(a)所有忠誠的將軍們制定相同的行動計劃
(b)少數叛徒不能導致忠誠的將軍們采納一個糟糕的計劃。
忠誠的將軍們會按照算法所說的去做,但叛徒們可以隨心所欲。算法必須保證條件(a),無論叛徒們做什么。忠誠的將軍們不僅要達成一致,而且要同意一個合理的計劃。
如果網絡中正確工作的節點能夠就它們的值達成一致,那么就可以實現拜占庭容錯。可以給缺失的消息指定一個默認投票值,也就是說,如果在一定時間限制內沒有收到來自特定節點的消息,我們可以假設該消息是“有故障的”。此外,如果大多數節點響應了正確的值,我們還可以分配一個默認響應。萊斯利·蘭伯特證明,如果我們有 3m+1 個正確工作的處理器,那么如果最多 m 個處理器有故障,就可以達成共識(對相同狀態的一致意見)。
二、PBFT流程
PBFT是一種狀態機副本復制算法,即服務作為狀態機進行建模,狀態機在分布式系統的不同節點進行副本復制。每個狀態機的副本都保存了服務的狀態,同時也實現了服務的操作。
所有的副本在一個被稱為視圖(View)的輪換過程中運作。在某個視圖中,一個副本作為主節點(primary),其它的副本節點作為備份節點(backups)。視圖是連續編號的整數。主節點由公式p = v mod |R|計算得到,v是視圖編號,p是副本編號,|R|是副本集合的個數。當主節點失效的時候就需要啟動視圖輪換過程。
在啟用 pBFT 的分布式系統中,節點按順序排列,其中一個節點是主節點(或領導者節點),其他節點被稱為次級節點(或備份節點)。請注意,系統中的任何符合條件的節點都可以通過從次級節點轉變為主節點來成為主節點(通常情況下,在主節點故障時)。目標是所有誠實節點通過多數規則幫助達成關于系統狀態的共識。一個實用的拜占庭容錯系統可以在滿足最大惡意節點數量不超過系統所有節點總數三分之一的前提下運行。隨著節點數量的增加,系統安全性會提高。pBFT 共識輪次分為四個階段(參考下圖):
1)客戶端發送請求給主節點
2)主節點廣播請求給其它節點,節點執行PBFT算法的三階段(pre-prepare階段( 預準備階段),prepare階段( 準備階段),commit 階段(提交階段))共識流程。
3)節點處理完三階段流程后,返回消息給客戶端。
4)客戶端收到來自 f+1 個節點的相同消息后,代表共識已經正確完成。
Request階段:在每一個視圖中會選擇一個主節點(這里假設是0節點),客戶端會發送請求給主節點。
Pre-prepare階段:節點收到pre-prepare消息后,會有兩種選擇,一種是接受,一 種是不接受。拒絕的邏輯就是主節點不會發送兩條具有相同的v和n,但d和m卻不同的消息。其中v是視圖編號,d是客戶端消息摘要,m是消息內容,n主要用于對客戶端的請求進行排序。
Prepare階段:副節點同意請求后會向其它節點(包括主節點)發送prepare消息。同一時刻不是只有一個節點在進行這個過程,可能有n個節點也在進行這個過程。同一個節點既在發prepare,也在收到其他節點的prepare消息。在一定時間范圍內,一個節點如果收到2f+1個不同節點的prepare消息,就代表prepare階段已經完成。
Commit階段:所有節點向其它節點廣播commit消息,同理,這個過程可能是有n個節點也在進行的。因此可能會收到其它節點發過來的commit消息,當收到2f+1條commit消息后(包括該節點本身),代表大多數節點已經進入commit階段,這一階段已經達成共識,于是節點就會執行請求,寫入數據。
Reply階段:客戶端如果收到f+1個相同的REPLY消息,說明客戶端發起的請求已經達成全網共識,否則客戶端需要判斷是否重新發送請求給主節點。
為什么prepare和commit階段都需要收到2f+1呢?
為了保證一致性,考慮最壞的情況:我們假設收到的有f個是正常節點發過來的,也有f個是惡意節點發過來的,那么,第2f+1個只可能是正常節點發過來的。(因為我們限制了最多只有f個惡意節點)由此可知,“大多數”正常的節點還是可以讓系統工作下去的。
為什么reply階段都需要收到2f+1呢?
我們還是來考慮最壞的情況,我們假設這f+1個相同的reply中,有f個都是惡意節點。
所以至少有一個rely是正常節點發出來的,因為在prepare階段,這個正常的節點已經可以保證prepared(m,v,n,i)為真,所以已經能代表大多數的意見,所以,client只需要f+1個相同的reply就能保證他拿到的是整個系統內“大多數正常節點“的意見,從而達到一致性。
三、PBFT算法的優缺點
(1)優點
A、PBFT算法具有高交易通量和吞吐量,高可用性,易于理解的優點。
B、解決了原始拜占庭容錯(BFT)算法效率不高的問題,將算法復雜度由指數級降低到多項式級,使得拜占庭容錯算法在實際系統應用中變得可行。
C、使用了加密技術來防止欺騙攻擊和重播攻擊,以及檢測被破壞的消息。消息包含了公鑰簽名(其實就是RSA算法)、消息驗證編碼(MAC)和無碰撞哈希函數生成的消息摘要(message digest)。
(2)缺點
PBFT算法的缺點:
A、計算效率依賴于參與協議的節點數量,由于每個副本節點都需要和其它節點進行P2P的共識同步,因此隨著節點的增多(100個左右時),性能會下降的很快,但在較少節點的情況下可以有不錯的性能,并且分叉的幾率很低,不適用于節點數量過大的區塊鏈,擴展性差。t同事由于節點較少pBFT 機制容易受到 Sybil 攻擊,即一個實體(一方)控制多個身份。
B、PBFT算法要求總節點數n>=3f+1(其中,f代表惡意節點數)。系統的失效節點數量不得超過全網節點的1/3,容錯率相對較低。
C、PBFT在網絡不穩定的情況下延遲很高。
四、PBFT算法的應用場景
PBFT算法的節點數量是固定的,節點身份提前確定,無法動態添加或刪除,只能適用于節點數目固定的聯盟鏈或私有鏈場景中。
PBFT在很多場景都有應用,在區塊鏈場景中,一般適合于對強一致性有要求的私有鏈和聯盟鏈場景,但如果能夠結合DPOS節點代表選舉規則,也可以應用于公有鏈,并且可以在一個不可信的網絡里解決拜占庭容錯問題。在Hyperledger Fabric項目中,共識模塊被設計成可插拔的模塊,支持像PBFT、Raft等共識算法。