PBFT共識算法詳解


PBFT(Practical Byzantine Fault Tolerance,實用拜占庭容錯)

一.概述

拜占庭將軍問題最早是由 Leslie Lamport 在 1982 年發表的論文《The Byzantine Generals Problem 》提出的, 他證明了在將軍總數大於 3f ,背叛者為f 或者更少時,忠誠的將軍可以達成命令上的一致,即 3f+1<=n 。算法復雜度為 O(nf+1) 。而 Miguel Castro 和 Barbara Liskov 在1999年發表的論文《 Practical Byzantine Fault Tolerance 》中首次提出 PBFT算法,該算法容錯數量也滿足 3f+1<=n,也即最大的容錯作惡節點數f=(n-1)/3。算法復雜度為 O(n2),將系統的復雜度由指數級別降低為多項式級別,使得拜占庭容錯算法在實際系統應用中變得可行。

那么為什么PBFT算法的容錯數量滿足3f+1<=n呢?

因為 PBFT 算法的除了需要支持容錯故障節點之外,還需要支持容錯作惡節點。假設集群節點數為 N,有問題的節點為 f。有問題的節點中,可以既是故障節點,也可以是作惡節點,或者只是故障節點或者只是作惡節點。那么會產生以下兩種極端情況:

  1. 這f 個有問題節點既是故障節點,又是作惡節點,那么根據少數服從多數的原則,集群里正常節點只需要比f個節點再多一個節點,即 f+1 個節點,確節點的數量就會比故障節點數量多,那么集群就能達成共識,即總節點數為f+(f+1)=n,也就是說這種情況支持的最大容錯節點數量是 (n-1)/2。
  2. 故障節點和作惡節點都是不同的節點。那么就會有 f 個作惡節點和 f 個故障節點,當發現節點是作惡節點后,會被集群排除在外,剩下 f 個故障節點,那么根據少數服從多數的原則,集群里正常節點只需要比f個節點再多一個節點,即 f+1 個節點,確節點的數量就會比故障節點數量多,那么集群就能達成共識。所以,所有類型的節點數量加起來就是 f+1 個正常節點,f個故障節點和f個作惡節點,即 3f+1=n。

結合上述兩種情況,因此PBFT算法支持的最大容錯節點數量是(n-1)/3。


二.PBFT共識算法流程

角色划分

  • Client:客戶端節點,負責發送交易請求。

  • Primary: 主節點,負責將交易打包成區塊和區塊共識,每輪共識過程中有且僅有一個Primary節點。

  • Replica: 副本節點,負責區塊共識,每輪共識過程中有多個Replica節點,每個Replica節點的處理過程類似。

其中,Primary和Replica節點都屬於共識節點。

算法流程

PBFT 算法的基本流程主要有以下四步:

  1. 客戶端發送請求給主節點
  2. 主節點廣播請求給其它節點,節點執行PBFT算法的三階段共識流程
  3. 節點處理完三階段流程后,返回消息給客戶端。
  4. 客戶端收到來自 f+1 個節點的相同消息后,代表共識已經正確完成。

算法的核心三個階段分別是 pre-prepare 階段(預准備階段),prepare 階段(准備階段), commit 階段(提交階段)。圖中的C代表客戶端,0,1,2,3 代表節點的編號,其中0 是主節點primary,打×的3代表可能是故障節點或者是作惡節點,這里表現的行為就是對其它節點的請求無響應。整個過程大致是如下:

首先,客戶端向主節點0發起請求<<REQUEST,o,t,c>> 其中t是時間戳,o表示操作,c是這個client,主節點收到客戶端請求,會向其它節點發送 pre-prepare 消息,其它節點就收到了pre-prepare 消息,就開始了這個核心三階段共識過程了。

  • Pre-prepare 階段:副本節點replica收到 pre-prepare 消息后,會有兩種選擇,一種是接受,一種是不接受。什么時候才不接受主節點發來的 pre-prepare 消息呢?一種典型的情況就是如果一個replica節點接受到了一條 pre-prepare 消息<<PRE_PREPARE,v,n,d>,m>,其中,v 代表視圖編號(視圖的編號是什么意思呢?比如當前主節點為 A,視圖編號為 1,如果主節點換成 B,那么視圖編號就為 2)n代表序號(主節點收到客戶端的每個請求都以一個編號來標記)d代表消息摘要m代表原始消息數據。消息里的 v 和 n 在之前收到里的消息是曾經出現過的,但是 d 和 m 卻和之前的消息不一致,或者請求編號n不在高低水位之間,這時候就會拒絕請求。拒絕的邏輯就是主節點不會發送兩條具有相同的 v 和 n ,但 d 和 m 卻不同的消息。

    Replia節點接收到pre-prepare消息,進行以下消息驗證:

    1. 消息m的簽名合法性,並且消息摘要d和消息m相匹配:d=hash(m)
    2. 節點當前處於視圖v中
    3. 節點當前在同一個(view v ,sequence n)上沒有其它pre-prepare消息,即不存在另外一個m'和對應的d' ,d'=hash(m')
    4. h<=n<=H,H和h代表序號n的高低水位。
  • Prepare 階段:當前節點同意請求后會向其它節點發送 prepare 消息 <PREPARE,v,n,d,i>同時將消息記錄到log中,其中i用於表示當前節點的身份。同一時刻不是只有一個節點在進行這個過程,可能有 n 個節點也在進行這個過程。因此節點是有可能收到其它節點發送的 prepare 消息的,當前節點i驗證這些prepare消息和自己發出的prepare消息的v,n,d三個數據是否都是一致的。驗證通過之后,當前節點i將prepared(m,v,n) 設置為true,prepared(m,v,n) 代表共識節點認為在(v,n)中針對消息m的Prepare階段是否已經完成。在一定時間范圍內,如果收到超過 2f 個其他節點的prepare 消息,就代表 prepare 階段已經完成。最后共識節點i發送commit消息並進入Commit階段。

  • Commit 階段:當前節點i接收到2f個來自其他共識節點的commit消息<COMMIT,v,n,d,i>同時將該消息插入log中(算上自己的共有2f+1個),驗證這些commit消息和自己發的commit消息的v,n,d三個數據都是一致后,共識節點將committed-local(m,v,n)設置為true,committed-local(m,v,n)代表共識節點確定消息m已經在整個系統中得到至少2f+1個節點的共識,而這保證了至少有f+1個non-faulty節點已經對消息m達成共識。於是節點就會執行請求,寫入數據。

處理完畢后,節點會返回消息<<REPLY,v,t,c,i,r>>給客戶端,當客戶端收集到f+1個消息后,共識完成,這就是PBFT算法的全部流程。


三.垃圾回收

根據前面的算法部分可以發現,我們需要不斷地往log中插入消息,在view change時恢復需要用到。於是log很快就會變得很占內存,這時候需要有一種方式清理掉無用的log。當某一request已經被f+1個正常節點執行完畢后,並當view change可以向其他節點證明當前狀態的正確性,與該request相關的message就可以刪除了。

每執行一個request就產生一次證明效率過於低下,論文中是每處理一定的request后產生一次證明。也就是當request的序號n % C ( 某 一 定 值 ) =0時,產生一個checkpoint,節點i多播消息<<CHECKPOINT,n,d,i>>給其他節點,當節點接收2f+1個消息時,該checkpoint變為stable checkpoint,也就是這2f+1個節點可以證明該狀態的正確性,同時可以刪除序號≤n的消息相關的log信息和checkpoint信息。

什么是 checkpoint 呢? checkpoint 就是當前節點處理的最新請求序號。前文已經提到主節點收到請求是會給請求記錄編號的。比如一個節點正在共識的一個請求編號是101,那么對於這個節點,它的 checkpoint 就是101。

什么是 stable checkpoint (穩定檢查點)呢?stable checkpoint 就是大部分節點 (2f+1個) 已經共識完成的最大請求序號。比如系統有 4 個節點,三個節點都已經共識完了的請求編號是 213 ,那么這個 213 就是 stable checkpoint 了,也就可以刪除213 號之前的記錄了。

什么是高低水位呢?低水位就是stable checkpoint的序號n,高水位是stable checkpoint的序號n + K,其中K是定值,一般是C(上面提及到的某一定值)的整數倍。


四.視圖更換(view change)

正常情況下,client將request發給一個主節點primary,然后主節點將request多播到其他節點replica,進行一個view。然而當主節點出錯或成為惡意節點時,就需要進行視圖更換(view change),也就是選擇(輪換法)下一個replica節點作為主節點,視圖編號v進行+1操作,共識過程進入下一個view。

如圖所示, view change 會有三個階段,分別是 view-changeview-change-acknew-view 階段。replica節點認為主節點primary有問題時,會向其它節點發送 view-change 消息<<VIEW−CHANGE,v+1,n,C,P,i>> 其中:

  • v:上一個視圖編號
  • n:節點i的stable checkpoint的編號
  • C:2f+1個節點的有效checkpoint信息的集合
  • P:節點i中的上一個視圖中編號大於n並且達到prepared狀態的請求消息的集合
  • i:節點的編號

當前存活的節點編號最小的節點將成為新的主節點。當新的主節點收到 2f 個其它節點的 view-change 消息,則證明有足夠多人的節點認為主節點有問題,於是就會向其它節點廣播 new-view 消息<<NEW-VIEW,v+1,V,O>>

其中:

  • v:上一個視圖編號

  • V:新的主節點接收到的有效的視圖編號為v+1的view-change消息集合

  • O:pre-prepare消息的集合。假設 O 集合里消息的編號范圍:(min~max),則 Min 為 V 集合最小的 stable checkpoint , Max 為 V 集合中最大序號的 prepare 消息。最后一步執行 O 集合里的 pre-preapare 消息,每條消息會有兩種情況: 如果 max-min>0,則產生消息 <<pre-prepare,v+1,n,d>> ;如果 max-min=0,則產生消息 <<pre-prepare,v+1,n,d(null)>>

注意:replica節點不會發起 new-view 事件。對於主節點,發送 new-view 消息后會繼續執行上個視圖未處理完的請求,從 pre-prepare 階段開始。其它節點驗證 new-view 消息通過后,就會處理主節點發來的 pre-prepare 消息,這時執行的過程就是前面描述的PBFT過程。到這時,正式進入 v+1 (視圖編號加1)的時代了。


五.優缺點

優點:

  • 通信復雜度O(n2),解決了原始拜占庭容錯(BFT)算法效率不高的問題,將算法復雜度由指數級降低到多項式級,使得拜占庭容錯算法在實際系統應用中變得可行。
  • 首次提出在異步網絡環境下使用狀態機副本復制協議,該算法可以工作在異步環境中,並且通過優化在早期算法的基礎上把響應性能提升了一個數量級以上。作者使用這個算法實現了拜占庭容錯的網絡文件系(NFS),性能測試證明了該系統僅比無副本復制的標准NFS慢了3%。
  • 使用了加密技術來防止欺騙攻擊和重播攻擊,以及檢測被破壞的消息。消息包含了公鑰簽名(RSA算法)、消息驗證編碼(MAC)和無碰撞哈希函數生成的消息摘要(message digest)。

缺點:

  • 僅僅適用於permissioned systems (聯盟鏈/私有鏈)。
  • 通信復雜度過高,可拓展性比較低,一般的系統在達到100左右的節點個數時,性能下降非常快。
  • PBFT在網絡不穩定的情況下延遲很高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM