爲什麼PBFT需要3個階段消息?

圖片不能顯示時,請查看原文::https://lessisbetter.site/2020/03/15/why-pbft-needs-3-phase-message/

前言

在面試的時候,很多同學的簡歷熟悉PBFT共識算法,在現場面試的時候,卻只能說個主要邏輯,離完整的算法,還差十萬八千里,相似從網絡上看了一些文章,就算是熟悉了。當我問“爲什麼PBFT需要3個階段消息?2個階段行不行”時,還沒有人能回答出來。

回答這個問題,還要從PBFT要解決的本質問題說起,所以我打算以這樣一個思路,爲大家回答問題:

  • PBFT與拜占庭問題
  • 拜占庭節點在網絡中的行爲
  • 什麼是3階段消息
  • 3階段消息解決什麼問題
  • 爲什麼不能只有前2個階段
  • 論文使用的2個不變性
  • 爲什麼3個階段可以達成一致性

PBFT與拜占庭問題

萊斯利·蘭波特在其論文[1]中描述瞭如下拜占庭問題:

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

問題在於,將軍中可能出現叛徒(壞將軍),他們不僅可能向較爲糟糕的策略投票,還可能選擇性地發送投票信息。阻止好將軍達成一致的形成策略。

摘自:維基百科:拜占庭將軍問題,有刪改。

很多人喜歡玩狼人殺,我也喜歡,但我玩的很菜,我用狼人殺跟拜占庭將軍問題做個類比。

在狼人殺開局的時候,你是好人,並且不知道自己的隊友是誰,也不知道狼人是誰,但所有的好人都有一個共同的目的:乾死狼人,好人獲勝。所以遊戲中需要使用技巧和策略,達成目的。

拜占庭將軍問題是類似的,好的將軍不知道其他將軍是好的,還是壞的,但所有好的將軍的目的是:行動一致,共同進退。所以,它們也需要策略達成一致。

BFT是一類解決拜占庭將軍問題的策略/算法:讓非拜占庭節點達成一致的算法。在這類論文中,拜占庭節點指“壞”的將軍,非拜占庭節點指“好”的將軍。

PBFT是實用拜占庭算法(Practical Byzantine Fault Tolerance)的縮寫,該論文與1999年發表,另外2001年又發表了一篇Practical Byzantine Fault Tolerance and Proactive Recovery,讓PBFT擁有恢復能力。

PBFT作爲解決拜占庭問題的策略:非拜占庭節點不知道哪些是拜占庭節點,哪些是非拜占庭節點,PBFT要讓非拜占庭節點達成一致

拜占庭節點在網絡中的行爲

拜占庭問題是在分佈式對等網絡,對通信容錯所提出來的。在真實世界中,拜占庭問題是什麼樣的?

通常使用拜占庭行爲,描述拜占庭節點可能的行爲,拜占庭行爲有:

  • 任何不遵守協議的動作
  • 惡意代碼、節點
  • 代碼bug
  • 網絡故障、數據包損壞
  • 磁盤崩掉、重複丟失
  • 無權限時加入

什麼是3階段消息

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qmyy4RN7-1584263615373)(http://img.lessisbetter.site/2020-03-pbft-3-phase-message.png)]

3階段消息是:Pre-prepare、Prepare和Commit。每個消息都會包含數字簽名,證明消息的發送者,以及消息類型,下文中會省略。

Pre-prepare消息由主節點發出,包含:

  • 當前view:v
  • 主節點分配給請求的序號n
  • 請求的摘要d
  • 請求本身m

務必記牢,m、v、n、d,後面會使用縮寫

Prepare是副本節點收到Pre-prepare消息後,做出的響應,發送給所有副本節點,包含:

  • v
  • n
  • d

Prepared狀態:副本i有Pre-prepare消息,且收到2f個有效的Prepare消息。

副本i達到Prepared狀態,可以發送Commit消息,Commit消息的內容和Prepare消息內容相同,但消息類型和數字簽名是不同的,所以可以區分。

m可以使用d代替,所以Prepare和Commit消息使用d代替m,來節省通信量。

3階段消息解決什麼問題

前面提到,PBFT解決的是拜占庭問題的一致性,即讓非拜占庭節點達成一致。更具體的說:讓請求m,在view內使用序號n,並且完成執行m,向客戶端發送響應

爲什麼不能只有前2個階段消息

這個問題的等價問題是:爲什麼Pre-prepare和Prepare消息,不能讓非拜占庭節點達成一致?

Pre-prepare消息的目的是,主節點爲請求m,分配了視圖v和序號n,讓至少f+1個非拜占庭節點對這個分配組合<m, v, n>達成一致,並且不存在<m', v, n>,即不存在有2個消息使用同一個v和n的情況。

Prepared狀態可以證明非拜占庭節點在只有請求m使用<v, n>上達成一致。主節點本身是認可<m, v, n>的,所以副本只需要收集2f個Prepare消息,而不是2f+1個Prepare消息,就可以計算出至少f個副本節點是非拜占庭節點,它們認可m使用<v, n>,並且沒有另外1個消息可以使用<v, n>

既然1個<v, n>只能對應1個請求m了,達到Prepared狀態後,副本i執行請求m,不就達成一致了麼?

並不能。Prepared是一個局部視角,不是全局一致,即副本i看到了非拜占庭節點認可了<m, v, n>,但整個系統包含3f+1個節點,異步的系統中,存在丟包、延時、拜占庭節點故意向部分節點發送Prepare等拜占庭行文,副本i無法確定,其他副本也達到Prepared狀態。如果少於f個副本成爲Prepared狀態,然後執行了請求m,系統就出現了不一致。

所以,前2個階段的消息,並不能讓非拜占庭節點達成一致。

如果你瞭解2PC或者Paxos,我相信可以更容易理解上面的描述。2PC或Paxos,第一步只是用來鎖定資源,第2步纔是真正去Do Action。把Pre-prepare和Prepare理解爲第一步,資源是<v, n>,只有第一步是達不成一致性的。

2個不變性

PBFT的論文提到了2個不變性,這2個不變性,用來證明PBFT如何讓非拜占庭節點達成一致性

第1個不變性,它是由Pre-prepare和Prepare消息所共同確保的不變性:非拜占庭節點在同一個view內對請求的序號達成共識。關於這個不變性,已經在爲什麼不能只有前2個階段消息中論述過。

介紹第2個不變性之前,需要介紹2個定義。

  • committed-local:副本i已經是Prepared狀態,並且收到了2f+1個Commit消息。
  • committed:至少f+1個非拜占庭節點已經是Prepared狀態。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ppuxDV7L-1584263615375)(http://img.lessisbetter.site/2020-03-pbft-committed.png)]

第2個不變性,如果副本i是committed-local,那麼一定存在committed。

2f+1個Commit消息,去掉最多f個拜占庭節點僞造的消息,得出至少f+1個非拜占庭節點發送了Commit消息,即至少f+1個非拜占庭節點是Prepared狀態。所以第2個不變性成立。

爲什麼3個階段消息可以達成一致性

committed意味着有f+1個非拜占庭節點可以執行請求,而committed-local意味着,副本i看到了有f+1個非拜占庭節點可以執行請求,f+1個非拜占庭節點執行請求,也就達成了,讓非拜占庭節點一致。

雖然我前面使用了2PC和Paxos做類比,但不意味着PBFT的Commit階段就相當於,2PC和Paxos的第2步。因爲2PC和Paxos處理的CFT場景,不存在拜占庭節點,它們的主節點充當了統計功能,統計有多少節點完成了第一步。PBFT中節點是存在拜占庭節點的,主節點並不是可靠(信)的,不能依賴主節點統計是否有f+1個非拜占庭節點達成了Prepared,而是每個節點各自統計,committed-local讓節點看到了,系統一定可以達成一致,纔去執行請求。

總結

本文介紹了2個階段消息是無法達成一致的原因,而爲什麼3階段消息可以。最核心的還是要理解好,PBFT解決了什麼問題,以及它是如何解決的。

PBFT解決的是在拜占庭環境下,如何提供一致性,以及如何持續的提供一致性的問題。本文只介紹瞭如何提供一致性,沒有提如何持續提供一致性,即PBFT的可用性。現在,不妨思考一下,View Change是如何保證切換時一致性的,是否也需要2個不變性的支持呢?

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