區塊鏈四:共識機制——PBFT算法深入講解

@TOC

背景介紹

共識機制是區塊鏈一大知識領域, 作用就是維持分佈式節點間的一致性,從而支撐去中心化中心,早在區塊鏈之前,分佈式系統就存在各種分佈式的共識機制,共識機制不是區塊鏈所發明,但區塊鏈卻對共識機制推廣和進步有着重要影響。

共識算法分類

按應用場景分,共識算法可以分成兩大類, 1、有壞人節點, 2、無壞人節點。
1、 有壞人節點,典型拜占庭問題,即系統中可能出現故意傳送假結果的節點導致分佈式系統結果錯誤,這種場景重點是在存在壞人的情況下能達成大家認可的一致結果。 其中BFT,PBFT, POW,POS都屬於這類。
2、 無壞人幾點,此類分佈式共識算法,只需要保證各節點行動一致,並在部分節點down後能繼續工作,一般在封閉式的分佈系統使用,其中有Raft,Paxos。

對幾種常見共識算法,大都類似的思路, 就是 一個組長(primary)帶着N個成員(backup)幹活,由組長派活收集各節點的狀態,再確定結果是否一致, 類似分佈式事務的二段提交。

其中不同算法主要解決這幾個問題思路不一樣,

  1. 系統判斷達成一致?
  2. 組長down了或部分節點down了怎樣保持系統可用性?
  3. 出現分叉了怎樣處理兩邊的結果?

PBFT

這部分就講解PBFT算法,怎樣解決以上幾個問題。
PBFT的算法思想, 以狀態機運作,包括節點狀態,消息狀態, 由組長帶領大家統一步調處理消息,而消息的是否繼續遷移下一個狀態,則通過多少節點達成一致,最後消息達到處理完的狀態。

消息處理:

消息狀態遷移路徑: request -> pre-prepare -> prepare-> commit -> reply
在這裏插入圖片描述

C 代表Client, 客戶端向系統主節點(0:組長)發送一請求request, 請求開始進入處理階段
pre-prepare : 主節點參與把request分配一個唯一的編號 request-number n, 並把request跟n一起組成pre-prepare消息廣播給所有成員(backup節點)

prepare : 所有成員(backup節點),收到pre-prepare消息, 依靠簽名字段檢查消息是否來源於主節點,確認無誤,將request編號和本節點簽名組成prepare消息,廣播給其他所有成員,表示自己認可這請求編號和準備好了。

Commit :所有節點,若收到的prepare消息,依靠簽名檢查是否正確,若prepare消息數量超過全部節點數量的3分之二, 則認爲系統達成一致認可該請求和請求編號,對所有節點廣播commit消息,表示該節點可以進行request的業務。

Reply : 所有節點, 若收到commit消息,依靠簽名檢查消息是否正確,若commit的消息數量超過所有節點的3分之一,則完成request要求的業務,並構建reply消息,直接回復給client。Client根據是否收到超過3分之1個節點的正確回覆,判斷系統是否完成了請求request。

上面的圖及說明就是PBFT的請求處理過程,那麼回到上面的問題,

問題一:系統判斷達成一致?
這裏分兩個階段,prepare, commit, 全網超過3分之二個prepare,則達成一致, commit超過三分之一則達成一致。

簡單說就是壞幾點要少於 三分之一。

靈魂拷問

1、爲啥是少於三分之一,而不是少於二分之一?
如果是多數服從多數,二分之一確實能滿足,但這裏是有兩個階段 prepare, commit。
n個節點,設錯誤節點 f, 第1到f個是錯誤節點, f+1 到n 是好節點pre-prepare -prepare, n-f 個節點都正確廣播 prepare消息,prepare-commit, n-f個好節點又k節點發生了view-change (下面有講解)或者其他狀況,那麼最終commit就達不到true。

n-f-k > f, 其中 k < (n-f)/2 得 n>2f + (n-f)/2 n>3f
得到 f 只能少於三分之一節點。

從上面的說明也知道,如果對於請求request r1 若commit(m) 成功達成一致,則不可能存在 commit(m’) 也達成一致,因此不可能存在分叉的情況。這裏也回答了第三個問題(問題三,出現分叉了怎樣處理兩邊的結果,不存在的)。

追問

爲啥要分開兩階段,一階段就搞掂不香嗎?
——這裏是爲了保證request的順序,第一階段分配順序號,第二階段纔是做業務。

這裏也提到commit階段可能k節點做視圖轉換,這是什麼?
——這就涉及第二個問題,下面分曉。

問題二: 組長down了或部分節點down了怎樣保持系統可用性?

視圖轉換

上面保證分佈式系統的正確性safety,做正確的事,而視圖轉換則是爲了可用性liveness, 假如primary節點down了,系統怎樣? 要保證系統繼續可用,就要使用view-change。

PBFT有一個全局的視圖編號view number: v,主節點primary是根據 v mod n =i 得到 節點i爲主節點。視圖轉換,就是v遞增,主節點primary也相應轉移到另一個節點。

  1. 當client發送請求primary後,一定時間沒收到回覆,則會發送請求給其他backup節點, backup 節點收到request後,起一個timer,如果timer過期,還沒執行這個request(commit還沒達一致),則backup節點發起view-change

  2. Backup 節點會廣播一個view-change 消息,包含原來視圖編號 v 合下個視圖編號v+1
    如果節點收到的view-change 消息多於三分之二,則說明view-change達成一致。

  3. 當 v+1 mod n = j , 新的primary節點j,收到足夠的view-change消息後, 就廣播new-view消息,告訴其他節點使用新視圖。

  4. 其他節點收到new-view後,確認消息簽名正確,進入新視圖;

有了視圖轉換,如果主節點down了,就會觸發視圖轉換更換另一個主節點,如果下一個主節點也是down的,則繼續切換,直到找到可用的主節點。因此保證只有有超過三分二的節點是好的,系統就可用。

可用性liveness,還要保證當視1圖轉換時候,可能有節點已經commit序列n,而有的節點只commit到序列n-1.,轉移視圖後,怎樣保證request在各節點都能正確一致執行。
這還要引出下問題,checkpoint 機制。

Checkpoint機制:

這裏就需要checkpoint, 這裏checkpoint跟其他系統日誌checkpoint基本一樣, 主要過程。系統定期創建checkpoint,記錄最新穩定提交的操作,並廣播checkpoint消息,當節點收到超過三分之二的創建checkpoint消息,該checkpoint達成一致。視圖轉換時候帶上最新的checkpoint,在checkpoint以後的請求,視爲不穩定的,需要重做。

總結

PBFT算法是通過節點消息狀態機方式達成請求處理的一致性,再通過視圖轉換,checkpoint機制確保系統的可用性,而本文概要介紹了這幾方面的原理,但也過濾具體算法細節,有興趣建議查看論文【引用1】

1 PBFT算法論文 http://pmg.csail.mit.edu/papers/osdi99.pdf

歷史

區塊鏈三:深入解析比特幣交易原理
區塊鏈二:比特幣的區塊數據結構
區塊鏈一 :區塊鏈應用介紹和展望

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