PBFT算法流程


轉載原址:https://my.oschina.net/u/3620978/blog/3142775

1. 系統模型

本部分介紹PBFT算法運行的系統模型。

1.1 網絡

PBFT工作在異步的分布式系統中,系統中各個節點彼此通過網絡連接。 系統運行時,消息的傳遞允許出現下列情形:不能正確發送、延遲、重復、亂序

1.2 拜占庭錯誤節點

系統允許錯誤節點也就是拜占庭節點表現出任意行為,但是需要附加一個限定條件: 節點失效彼此應相互獨立,從而大部分或全部節點不會同時失效。
在有惡意攻擊存在的情況下,可以采取類似於下列措施來保證這個限制的成立:各節點運行的服務程序和操作系統的版本盡可能多樣化;各節點的管理員帳號和密碼不同。

1.3 消息加密屬性

1.3.1 使用加密技術的目的

防止身份欺騙、重播攻擊;監測錯誤消息

1.3.2 具體使用的加密技術

公鑰簽名:用於驗證消息發送者身份,PBFT中,實際上只用於view-change和new-view消息,以及出現錯誤的情況。其他消息都采用下面將會提到的MAC(消息認證碼)進行認證。這是算法設計中提出的一種優化措施,用於提升算法性能。
MAC:即消息認證碼,用於算法正常操作流程中的消息認證
消息摘要:用於檢測錯誤消息

1.4 敵手特性

算法限定敵手(adversary)可以:串通拜占庭節點;延遲通信或正常節點。
同時,敵手不可以:無限延遲正常節點的通信;偽造正常節點簽名;從消息摘要反推原始消息;讓不同消息產生相同摘要。

2. 服務屬性

本部分介紹運行PBFT算法的系統的服務屬性。

2.1 關於副本復制服務

PBFT算法可用於實現確定性的副本復制服務(Replicated service)。 副本復制服務擁有狀態(state)和操作(operation)。
客戶端(client)向服務發起請求,以執行操作,並等待響應。
服務由 n個節點組成。操作可以執行任何計算,只要這些計算始終產生確定性的結果。
節點和客戶端如果遵循算法的預定步驟執行操作,則被稱為正常節點或客戶端。

2.2 關於Safety和Liveness

只要系統中失效節點的個數不超過容錯數 ,系統就能提供safety和liveness。

2.2.1 Safety

Safety的提供,是系統能保證客戶端請求的線性一致性(linearizability),即請求按順序一次一條地被執行。
PBFT相對於之前的算法如Rampart等的一個顯著的不同在於,其Safety不依賴於同步假設。
算法不需限定客戶端一定是正常的,允許其發送不合法的請求,原因是各正常節點可以一致性地監測客戶端請求的各種操作。並且算法可以通過權限控制的方式對客戶端進行限制。

2.2.2 Liveness

由於算法不依賴於同步提供 Safety,因此必須通過同步假設來提供 Liveness。
這里的同步假設是,客戶端的請求最終總能在有限的時間內被系統接收到。
客戶端可能會通過多次重傳的方式,發送請求到服務,確保其被服務接收到。
PBFT所依賴的同步假設其實是比較弱的假設,原因是在真實的系統中,網絡錯誤最終總可以修復。

2.3 關於算法彈性

PBFT的算法彈性(resiliency)是最優的:假定系統中失效節點最大個數為f,則系統最少只需要 3f+1 個節點就可以保證Safety和Liveness。

簡單證明:
考慮到最不理想的情況,系統有最大數量的失效節點,即f個。(總節點數為n) 客戶端此時可以接收到的回復個數最壞情況是 n-f,因為失效節點可能都不會回復。 但是,由於網絡等原因,客戶端接收到的 n-f 個請求中,實際上有可能包含有失效節點的回復(有可能是錯誤的),而另外一些正常節點的回復還未及時收到。 這其中,最壞的情況是,n-f個結果中,有f個是失效節點發送的。按照PBFT算法的定義,客戶端需要收到 f+1 個相同的回復,才被當作是正確的結果。因此 n-f 個結果中,出去f個失效節點的結果,即 n-f-f = n-2f 至少要是f+1, 即 n-2f = f+1,也就是說 n=3f+1是最少需要的節點數量。

2.4 關於信息保密性

一般情況下,為確保服務的高效性,不能提供容錯的信息保密性。
可能可以使用secret sharing scheme來獲得操作參數和部分對操作來說透明的狀態的保密性。

3. 算法主流程

本部分介紹運行PBFT算法的主流程,即正常操作流程。

3.1 主流程簡介

3.1.1 相關定義

算法是狀態機副本復制技術的一種形式:服務被建模為狀態機,其狀態在分布式系統中的不同副本節點上被復制。每個狀態機副本節點保存維護着服務狀態,並實現服務的各種操作。

假設所有副本節點個數為n,算法中,每個節點依次編號為 0, 1, ..., n-1

方便起見,假設系統中的副本節點總數為 3f+1。可以有更多數量的節點,但是這不會使算法的彈性更優,只會使系統的性能降低。

系統在稱為視圖(view)的配置下工作。視圖以整數編號,從0開始。在一個具體的視圖 v 中,通過 p =v mod n,決定出主節點(primary),而其余節點成為副本節點(backup)。當主節點失效時,進行視圖變更(view change)。視圖的編號是連續遞增的。

3.1.2 算法主流程簡要描述

算法主流程可簡要描述如下:
1. 客戶端通過向主節點發送請求,以調用服務的操作;
2. 主節點向其他所有副本節點廣播該請求;
3. 各節點執行客戶請求,同時將回復發送到客戶端;
4. 客戶端收到 f+1 個來自不同節點的相同的回復后,此回復即為本次請求的結果。

因為算法基於狀態機副本復制技術,所以節點需滿足兩個條件:必須是確定性的,即對於給定的狀態,以及給定的參數集合,調用相同的操作后,將始終得到相同的結果。

各節點擁有相同的初始狀態。

在滿足上述兩個條件的情況下,算法可以保證系統的Safety屬性:即使存在失效的節點,各正常副本節點仍可以就不同的請求的執行順序達成總體的一致。

3.2 算法主流程

接下來詳細描述算法主流程。為方便起見,這里省略討論以下細節:
節點因空間不足導致錯誤,以及如何恢復;
類似網絡的原因等導致的客戶端消息的重傳。

另外,假設消息使用公鑰簽名進行認證,而不是更高效的 MAC 的方式。算法流程的啟動從客戶端發送請求開始。

3.2.1 客戶端操作

客戶端操作流程示意圖如下:



客戶端向其認為的Primary節點發送請求:<REQUEST, o, t, c >。其中,o是請求的操作,t是時間戳,c代表客戶端信息。這里省略了消息的簽名,包括下文提到的所有消息都應該有發送方的簽名,為了討論方便,作了省略。

相關的幾點說明:
請求中的時間戳用於保證請求只被執行一次的語義:所有的時間戳都嚴格排序,即后發送的請求比先發送的請求擁有更高的時間戳。
每個副本節點向客戶端發送回復時,都會包含當前的視圖編號。客戶端可以通過該視圖編號來確定當前的主節點,並且只向其認為的主節點發送請求。

每個副本節點執行完請求后,各自單獨地向客戶端發送回復,其格式為: <REPLY, v, t, c, i, r > 。v是當前的視圖編號,t是請求發送時對應的時間戳,i是副本節點的編號,r是請求的操作的執行結果。

客戶端等待來自 f+1 個不同副本節點的相同回復,即t和r要相同。如果客戶端等到了 f+1 個相同回復,r即為請求的結果。 之所以該結果是有效的,是因為錯誤節點的個數最多為f個,因此必然至少有一個正常節點回復了正確結果,此結果就是 r。

如果客戶端沒有及時收到回復,則會將請求廣播給所有副本節點。副本節點收到請求后,如果發現已經執行過該請求,就只是將結果重新發送至客戶端;否則,它會把請求轉發到主節點。如果主節點沒有把請求廣播給其他節點,則最終會被足夠多的副本節點認定為錯誤節點,從而觸發視圖變更。

在接下的流程討論中,假定客戶端等待一個請求完成后,才發送下一個請求。但是,算法允許客戶端異步地發送請求,並且可以保證不同請求按順序執行。

3.2.2 三階段協議

主節點收到客戶端請求后,將啟動三階段協議,也就是算法接下來的流程。

這三階段是pre-prepare,prepare和commit。前兩階段,即 pre-prepare 和 prepare 用於保證當前視圖中請求被排好序,而后兩階段 prepare 和 commit 保證請求在視圖變更后,仍舊是排好序的。

3.2.2.1 pre-prepare階段

pre-prepare 階段流程示意圖如下:

pre-prepare階段中,主節點組裝預准備消息,同時把客戶端請求附加在其后:<<PRE-PREPARE, v, n, d>, m>,其中,v 指示當前消息當前在哪個視圖中被編號和發送,m 是客戶端的請求消息,n是主節點給 m 分配的一個序號(sequence number), d 是 m 的摘要。

這里需要注意的是,請求 m 並沒有放在預准備消息中,這樣做可以使預准備消息變得更簡短。這樣做有兩個好處:
1、降低通信的負載:在視圖變更時,由於各節點收到的預准備消息會被用來證明一個特定的請求確實在特定的視圖中被賦予了一個序號,較簡短的預准備消息將使數據傳輸量更少。
2、有助於傳輸優化:算法運行中,一方面需要向各節點發送客戶端請求,另一方面需要傳輸協議消息以實現對客戶請求的排序。通過對這兩者解耦,可以實現對較小的協議消息的傳輸以及對應於較大的請求的大消息的傳輸分別進行優化。
每個副本節點接收到預准備消息后,會進行如下校驗,如果條件都滿足的話,就接受該消息;否則就什么也不做:
客戶端請求和預准備消息的簽名都正確;d 和 m的消息摘要一致;
當前節點的當前視圖是v;
當前節點未曾接受另外一條預准備消息,其包含的視圖編號和消息序號都和本條消息相同,但對應的是不同的客戶端請求;
預准備消息中的序號 n 位於低水線 h 和高水線 H 之間。這是為了防止有可能出錯的主節點隨意地選擇序號來耗盡序號空間,例如故意選擇一個非常大的序號。

如果副本節點接受預准備消息,接下來就進入prepare 階段,如下節所示。

3.2.2.2 prepare階段

prepare 階段流程示意圖如下:

在 prepare 階段,節點會組裝並廣播准備消息給其他所有副本節點,同時把預准備和准備消息寫入到本地消息日志中。

准備消息格式如下: <PREPARE, v, n, d, i>。其中,i 為節點編號,其余參數和預准備消息中的含義相同。

對於副本節點(包括主節點)來說,當其收到其他節點發送過來的准備消息時,會對這些消息進行校驗,如果這些消息滿足下列條件:
簽名正確
其視圖編號和節點的當前視圖編號相同
消息中的序號在 h 和 H 之間

則節點會接受准備消息,並寫入消息日志中。

對於一個副本節點 i 來說,如果其消息日志中包含如下消息:
客戶端請求 m
在視圖 v 中將 m 分配序號 n 的預准備消息
2f個由不同的副本節點發送的、和預准備消息相匹配的准備消息;這里匹配的含義是,有相同的視圖編號、請求序號,以及消息摘要。

我們就稱prepared(m, v, n, i)為true。

算法的預准備和准備階段用於保證所有的正常副本節點就同一視圖中的所有請求的順序達成一致。具體來說,這兩階段能確保以下不變式:
如果prepared(m, v, n, i)為true,則對任意一個正常的副本節點j(包含i)來說,prepared(m', v, n, j)肯定為false,這里m'是不同於m的一個請求。

簡單證明如下:
因為prepared(m, v, n, i)為true,而錯誤節點最多為f個,所以至少有f個正常節點發送了准備消息,再加上主節點,這樣至少有f+1個節點已經就m在視圖v中被編號為n達成了一致。因此,如果prepared(m', v, n, j)為true,意味着上述f+1個節點中至少有一個節點發送了兩個相互矛盾的預准備或准備消息,也就是說,這些消息擁有相同的視圖編號和序號,但是對應着不同的請求消息。但這是不可能的,因為該節點是正常節點,因此prepared(m', v, n, j)一定為false。

對於副本節點i來說,prepared(m, v, n, i)變為true,則其將進入commit階段,如下節所示。

3.2.2.3 commit階段

commit 階段流程示意圖如下:

節點進入 commit 階段時,副本節點i將向其他所有副本節點廣播確認消息:
<COMMIT, v, n, D(m), i>,
對於副本節點來說,當其收到其他節點發來的確認消息的時候,會判斷其是否滿足下列條件:
簽名正確;
消息中的視圖編號等於當前節點的視圖編號;
消息中的請求序號在h和H之間。

如果以上條件均滿足,則節點則會接受確認消息並寫入本地的日志消息中。

對於副本節點i來說,如果:prepared(m, v, n, i)為true,並且已經接受了 2f+1 個來自不同節點的、和 m 對應的預准備消息相匹配的確認消息(可能包含它自己的)。則我們稱 committed-local(m, v, n, i) 為 true。這里確認消息和預准備消息匹配的含義是,它們有相同的視圖編號、消息序號,以及消息摘要。

另外,如果至少存在 f+1 個節點,對於其中每一個節點i來說,如果 prepared(m, v, n, i) 為true,我們則稱committed(m, v, n) 為 true。

commit 階段能保證以下不變式:如果對某個副本節點來說,committed-local(m, v, n, i) 為 true,則 committed(m, v, n) s也為true。

上述不變式和視圖變更協議一起能夠保證:所有正常節點能夠就所有本地確認的請求的序號達成一致,即使這些請求是在不同的視圖中確認的。對應的證明將在另外一篇文檔中給出。

另外,該不變式也能保證:任何一個請求如果在一個副本節點被確認,那么它最終也會被至少 f+1 個副本節點確認。

對於任何一個副本節點i來說,如果:committed-local(m, v, n, i) 為 true,i 的狀態反映了所有序號小於 n 的請求順序執行的結果。此時,它就可以執行 m 所請求的操作。這就保證了所有的正常節點,按相同的順序執行請求,從而保證算法的安全性。

在執行了請求的操作后,每個節點單獨地給客戶端發送回復。對於同樣內容的請求,節點會忽略那些時間戳更早的,以保證請求只被執行一次。

此外,算法並不要求消息按順序投遞,因此,節點可以亂序確認請求。這樣做沒有問題,因為算法只在一個請求對應的預准備、准備和確認消息都收集完全時才會執行該請求。

以下是 f=1,即失效節點數為1個,總共節點數為 4個時,PBFT 算法的運行示意圖:

4.視圖變更、垃圾回收及狀態機不確定性

4.1垃圾回收

本部分介紹PBFT算法的垃圾回收機制。

4.1.1 概述

本節介紹從本地日志中刪除歷史消息的機制。

對算法來說,為了保證安全性,每個副本節點需要保證如下兩點:
對於每個請求來說,在被至少f+1個正常節點執行之前,所有相關的消息都必須記錄在消息日志中;
同時,如果一條請求被執行,節點能夠在視圖變更中向其他節點證明這一點。

此外,如果某個副本節點缺失的一些消息正好已經被所有正常節點刪除,則需要通過傳輸部分或全部的服務狀態來使節點狀態更新到最新。因此,節點需要某種方式來證明狀態的正確性。

如果每執行一次操作,都生成一個狀態證明,代價將會很大。因此可以每執行一定數量的請求后生成一次狀態證明,例如:只要節點序號是某個值比如100的整數倍時,就生成一次,此時稱這個狀態為檢查點。如果一個檢查點帶有相應的證明,我們則稱其為穩定的檢查點。

4.1.2 穩定檢查點的生成

如上所述,一個帶有證明的檢查點被稱為穩定的檢查點,這種證明的生成過程如下:
1、副本節點i生成一個檢查點之后,會組裝檢查點消息,並全網廣播給其他所有副本節點,檢查點消息格式如下:
<CHECKPOINT, n, d, i>,
這里n指的是生成目前最新狀態的最后一條執行請求的序號,d是當前服務狀態的摘要。

2、每個副本節點等待並收集 2f+1 個來自其它副本節點的檢查點消息(有可能包括自己的),這些消息有相同的序號 n 和摘要 d。這 2f+1 個檢查點消息就是該檢查點的正確性證明。

一旦一個檢查點成為穩定檢查點后,節點將從本地消息日志中刪除所有序號小於或等於n的請求所對應的預准備、准備和確認消息。同時,會刪除所有更早的檢查點和對應的檢查點消息。
檢查點的生成協議可以用來移動低水線 h 和高水線 H:
h的值就是最新穩定檢查點所對應的穩定消息序號;
高水線 H = h+k,這里k要設置足夠大,至少要大於檢查點的生成周期,比如說:假如每隔100條請求生成檢查點,k就可以取200。

4.2 視圖變更

PBFT算法運行過程中,如果主節點失效了,為了保持系統的活性(liveness),就需要用到視圖變更協議。

4.2.1 視圖變更的觸發

由於主節點失效時,客戶端最終會將請求發送到所有其他副本節點。每個節點收到客戶端請求后,如果該請求沒有執行過,副本節點判斷自己是否為主節點,不是的話就會把請求轉發給主節點,同時啟動一個定時器(假如之前沒有啟動過的話)。

如果請求在定時器時間間隔內執行完,則節點會停止定時器(不過如果此時節點恰好在等待執行另外一個請求,則會重啟定時器);否則,節點會嘗試觸發視圖的變更,具體過程如下節所示。

4.2.2 視圖變更協議

對於副本節點i來說,假設其當前所處的視圖編號為 v ,經由視圖變更協議,從視圖 v 變更到 v+1。

視圖變更過程中,節點將不再接受其他任何類型的消息,只接受 checkpoint, view-change, 和 new-view 消息。

視圖變更過程如下:
1. 節點組裝 VIEW-CHANGE 消息並廣播給全網其他所有副本節點。
VIEW-CHANGE消息的格式如下:
<VIEW-CHANGE, v+1, n, C, P, i>
消息中的各字段含義如下:
v+1: 要變更到的目標視圖編號;
n: 對應於節點已知的、最新的檢查點 s 的請求序號;
C:包含 2f+1 個檢查點消息的集合。這些檢查點消息用於證明檢查點 s 的正確性;
P:是一個集合,現在來解釋一下其包含的信息。
對於任何一條客戶端請求 m ,如果 m 在當前副本節點 i 上已經准備好, 即 prepared(m, v, n', i) 為 true, 並且 n' > n,那么根據定義,節點上已經存儲了對應的預准備消息和 2f 個與之匹配的、有效的發自不同的節點的准備消息。這里,匹配的含義是:擁有相同的視圖,消息序號以及 m 的摘要。我們把這些預准備
消息和准備消息組成的集合記為 。
P 就是所有 組成的集合。因此,P 包含了所有在副本節點上准備好的、序號大於 n 的請求的預准備和准備消息。在視圖變更中,其提供的信息便於在新的視圖中重新分配每條請求的消息序號。
2. 每個節點相繼廣播各自組裝的 view-change 消息。同時,新視圖中對應的新的主節點將收集來自其他副本節點的 view-change 消息。當其收集到 2f 個有效的 對應新視圖 v+1 的 view-change 消息后,將組裝並廣播 new-view 消息,格式如下:
<NEW-VIEW, v+1, V, O>
其中,V是一個消息集合,包含所有有效的、對應於新視圖 v+1 的 2f+1 個 view-change 消息(包括主節點自己組裝的)。而 O 則是主節點為各 view-change 消息中包含的、符合要求的請求組裝的預准備消息的集合。 O中的消息按如下方式組裝:
首先,根據 V 中各條view-change 消息中包含的預准備和准備消息,主節點先找到最新的穩定檢查點,將其對應的消息序號賦值給 min-s;然后從所有准備消息中找到最大的那個消息序號,將其賦值給 max-s;
然后,對於min-s 和 max-s 之間的每一個消息序號 n, 主節點為其組裝位於視圖 v+1 上的預准備消息,這分為兩種情況:
a) 在 V 中存在某個或多個 view-change 消息, 它們的 P 集合中的某個集合元素包含的准備消息中包含有對應於序號 n 的消息。
此時,主節點組裝的預准備消息如下:
<PRE-PREPARE, v+1, n, d>
其中,d 是V中特定請求消息的摘要,並且該請求在 V 中的一個最新視圖上的預准備消息中被分配了序號 n 。
b) 另外一種情況,是 V 中不存在和 n 對應的准備消息。此時,主節點只是模擬為一個特殊的空請求(null request)組裝一個預准備消息:
<PRE-PREPARE, v+1, n, D(null)>
其中,D(null) 為空請求的摘要。空請求和其他請求一樣進行三階段協議,但是其執行就是一個空操作(noop)。

3. 主節點廣播 new-view 消息后,也會把 O 中的消息寫入本地消息日志中。同時,如果主節點本地的最新穩定檢查點的消息序號落后於 min-s 的話,則會將 min-s 對應的檢查點的證明,也就是相應的檢查點消息寫入消息日志,並按之前介紹的垃圾回收機制刪除所有的歷史消息。

4. 此時,主節點正式變更到新視圖 v+1, 開始接收消息。

5. 每個副本節點收到針對 v+1 視圖的 new-view 消息后,會進行校驗,是否滿足以下條件:
簽名正確;
其中包含的 view-change 消息是針對 v+1 視圖,並且有效;
集合 O 中的信息正確、有效。節點判斷有效與否的方法是進行類似於主節點生成 O 那樣的計算。
如果校驗通過,副本節點會將相關信息寫入到本地日志中。 同時,針對 O 中的每一條預准備消息,組裝並廣播對應的准備消息,並且把准備消息寫入到本地消息日志中。
此時,副本節點也如同主節點那樣,進入到新視圖 v+1 中。
之后,在新的視圖中,針對所有序號位於 min-s 和 max-s 之間的請求,系統會重新運行三階段協議。只不過對於每一個副本節點來說,如果當前確認的請求之前已經執行過的話,節點就不再執行該請求。每條被執行的請求,其相關信息會被存儲在本地。節點根據這些信息確定請求的執行情況。
以上完成了對視圖變更的介紹。

4.2.3 視圖變更中節點的信息同步

視圖變更時,由於 new-view 消息中並不包含原始的客戶端請求,因此副本節點可能缺失某條客戶端請求 m ,或者某個穩定的檢查點。

此時節點可以從其他副本節點同步缺失的信息。例如,假如節點 i 缺失某個穩定檢查點 s ,這個檢查點在 V 中可以找到相應的證明,也就是 對應的 checkpoint 消息。由於總共有 2f+1個這樣的消息,而錯誤節點最多 f個,因此至少有 f+1 個正常節點發送過這樣的消息。因此,可以從這些正常節點獲取到對應的檢查點狀態。

對於副本復制服務的狀態來說,可以通過生成不同的檢查點來划分狀態。當節點需要同步狀態時,只需按檢查點來獲取即可。這可以避免一次發送整個服務狀態。

4.3 關於狀態機的不確定性

PBFT算法基於狀態機副本復制服務,狀態機要求每個節點的狀態必須是確定性的。而大多數服務有時會有某種形式的不確定性。例如,對於網絡文件系統而言,如果不基於狀態機副本復制的話,文件的最后修改時間這個屬性可以設置為服務器的本地時間。但如果是每個副本節點獨自設置這個時間的話,就會導致各節點狀態的不一致。

因此,需要相應機制來確保各節點使用相同的值。一般情況下,這個值不應該由客戶端來決定,因為客戶端擁有的信息並不完全。例如,多個客戶端並發發送請求時,它們並不知曉其請求如何被排序。

可以由主節點來選取這個值,具體有兩種方法:
1. 第一種方法適用於大多數服務,由主節點獨立選取非確定的值。
主節點將該值和客戶端請求拼接在一起,然后運行三階段協議,確保所有正常節點就請求和該值的序號達成一致。這可以防止出現下列情況:
失效的主節點故意向不同的副本節點發送不同的值,從而使各個節點上的狀態出現不一致。
對於這種方法來說,雖然所有正常節點使用相同的值,但這個由主節點發送的值可能是錯誤的。這種情況下,要求每個副本節點必須能夠基於其狀態來明確地判斷該值的正確性,以及如何處理可能的錯誤值。

2. 第二種方法是該值的選取由各副本節點一起參與。這種方法要求在三階段協議基礎上額外增加一個階段:主節點收集各副本節點發過來的、可驗證來源的、共計 2f+1 個值,並把這些值和客戶端請求拼接在一起,然后運行三階段協議。 之后,每個副本節點基於這些值和各自的狀態進行確定的計算,從而得到所需選取的值。這種計算可以是類似於求中位數等。

5.算法正確性證明及優化

5.1 PBFT算法正確性證明

本部分介紹PBFT算法的正確性證明。

5.1.1 安全性(Safety)證明

PBFT算法提供的安全性(safety)的具體含義是,對於所有本地確認(commit locally)的客戶端請求來說,系統中所有正常副本節點都會就這些請求的消息序號達成一致。

上述的“達成一致”,其含義又分為兩種:

同一視圖中的消息序號一致:對於所有在同一視圖中本地確認的客戶端請求來說,各正常副本節點就其消息序號會達成一致。
新舊視圖中的消息序號一致:對於在新舊視圖中本地確認的客戶端請求來說,各正常副本節點就其消息序號會達成一致。


接下來分別證明上述兩種“一致”是成立的。

1. 在同一視圖中,任何一個請求 m ,如果其已經本地確認過,也就是說,至少對於某一個正常副本節點 i 來說,prepared(m, v, n, i) 為 true , 之前已經證明過,此時,對於任意的正常副本節點 j (j也可以是 i) 來說,prepared(m’, v, n, j) 都為 false 。這里 m’ 是不同於 m 的另一個請求,也就是說 D(m’) 不等於 D(m) 。這就意味着對於所有在同一視圖中本地確認的客戶端請求來說,各正常副本節點就其消息序號會達成一致,第一個性質成立。

2. 現在考慮存在視圖變更的情況。首先,在視圖 v 中,對於任意一個請求 m 來說,如果其在 某個正常副本節點 i 完成了本地確認,假設其消息序號為 n 。那么,就有 committed(m, v, n) 為 true 。 這也意味着存在一個節點集合R1, 其中至少含有 f+1 個正常副本節點,並且對於其中每一個節點 i ,prepared(m, v, n, i) 為 true。

然后,考慮系統最終變更視圖到 v' 的情況。在從視圖 v 變更到 v' 的過程中,此時變更沒有完成,正常副本節點在接收到 new-view 消息之前,不會接受視圖 v' 上的預准備消息。
但是,對於視圖 v 變更到 v'的任意一個有效的 new-view 消息來說,其中包含 2f+1 個有效的view-change 消息。這些消息來自不同的副本節點,記它們組成的集合為R2。R1和R2至少有一個相同的元素,也就是相同的節點。不然的話,它們總的節點個數將為(f+1) + (2f+1) = 3f+2,這與我們假定的系統總節點個數 3f+1 不符。

因此,假設這個共同的正常副本節點為 k 。對於請求 m 來說,只有可能存在下面兩種情況:new-view 消息中,存在 view-change 消息,其中包含的最新穩定檢查點對應的消息序號大於 m 的序號 n 。new-view 消息中所有的 view-change 消息中包含的最新穩定檢查點對應的消息序號不大於m的序號n。

對於第一種情況,根據視圖變更協議,新視圖 v' 中,所有正常副本節點不會接受序號為n或小於n的消息。

對於第二種情況,m 將會被傳播到新視圖 v'中,因為根據視圖變更協議,min-s≤n。視圖變更完成后,在 v' 中,算法將針對編號為 n 的請求 m 重新運行三階段協議。這就使得所有正常副本節點會達成一致,而不會出現下面這種情況:
另一個不同於 m 的請求 m' , 其在視圖 v 中分配的序號為 n ,且在新視圖中 v' 完成本地確認。
綜合上面 1 和 2 的證明,就證明了算法在同一視圖和視圖變更過程中,都會保證本地確認的請求的序號在所有正常副本節點中會達成一致,從而保證了算法的安全性(safety)。

5.1.2 活性(Liveness)保證

對於PBFT算法來說,為了保證系統的活性(liveness),當節點無法執行客戶端請求時,需要變更到新的視圖。同時,視圖變更也需要進行合理控制,只在需要時才進行,否則頻繁的視圖變更會影響到系統的活性。這就需要保證以下兩點:
系統中至少 2f+1 個正常副本節點處於同一視圖中時,這種狀態盡可能長時間地保持;
每次視圖變更時,上述時間間隔需要快速增長,比如以指數形式增長。


PBFT算法通過如下三種方法來保證上述兩點:

1. 為了防止視圖變更太快開始,當一個節點發送 view-change 消息后,在等待接收 2f+1 個 view-change消息時,會同時啟動定時器,其超時時間設置為 T。如果視圖變更沒有在 T 時間內完成,或者在新視圖中請求沒有在該時間間隔內完成,則會觸發新的視圖變更。此時,算法會調整超時時間,將其設置為原來的兩倍,即 2T 。

2. 除了上述的定時器超時觸發節點發送 view-change 消息外,當其接收到來自 f+1 個不同節點的有效view-change 消息,並且變更的目標視圖大於節點當前視圖時,也會觸發節點發送 view-change 消息。這可以防止節點過晚啟動視圖變更。

3. 基於上述第二點的規則,失效節點無法通過故意發送 view-change 消息來觸發頻繁的視圖變更從而干擾系統的運行。因為失效節點最多只能發送 f 條消息,達不到 f+1 的觸發條件。失效節點是主節點時,可能會觸發視圖變更,但是連續的視圖變更最多只會是 f 個,之后主節點就是正常節點。因此,基於以上的規則,系統可以保證活性。

5.2 PBFT算法的優化

本部分介紹PBFT算法的優化。這些優化方式應用於算法的正常操作中,可以提升算法的性能,同時可以保持系統的安全性和活性。

5.2.1 減少系統通信量

可以采用三種方法減少系統通信量:

1. 向客戶端發送回復的消息摘要,而不是回復的原始內容客戶端指定一個特定的副本節點,從該節點接收完整的回復內容,而只從其他所有節點處接收回復的摘要。通過判讀摘要與回復的一致性以及對回復計數,可以確保接收到正確的回復。如果客戶端接收不到正確結果,就會按正常流程重新請求系統,並接收不同節點的完整回復。

2. 請求在副本節點prepared后,節點即試探性地執行請求,並發送結果。客戶端只要收到 2f+1 個匹配的結果,就可以確保該結果的正確性。也就是說,該請求最終會確認(至少f+1 個正常副本節點的本地確認)。如果客戶端無法得到正確結果,就重新發送請求,系統執行正常流程。一個被試探性執行的請求,有可能在視圖變更過程中被中斷,並被替換為一個空請求。此時,已經執行過請求的節點可以通過 new-view 消息中的最新的穩定檢查點或本地的檢查點來更新狀態(取決於哪個序號更大)。

3. 針對只讀操作,客戶端將請求廣播到每一個副本節點。各節點判斷請求確實為只讀且滿足條件后,直接執行請求,並發送回復到客戶端。客戶端收到 2f+1 個相同的回復,即為正確結果;否則客戶端之前設置的重發請求定時器將觸發超時,使得客
戶端重發請求,系統執行正常流程。

這種優化的前提條件是,副本節點在執行請求之前,需確保之前所有請求都已確認,並且被執行。

 

5.2.1 加快消息驗證速度

使用公鑰簽名的方式驗證消息存在如下不足:

類似於RSA這樣的簽名算法,簽名速度比較慢;

其他公鑰密碼系統,如橢圓曲線公鑰密碼系統,雖然簽名更快,但是驗簽更慢。

 

PBFT算法實際上在正常流程中采用 MAC(Message Authentication Code,消息驗證碼) 認證消息,因為它具有如下優點,使得算法相對於之前的算法性能提升了一個數量級以上:

MAC 計算速度快;

通過適當優化,可以減少其長度;

通過對authenticator(vector of MAC)的使用,可以使驗證時間為常量,而生成時間只隨着節點數量線性增長。

 

具體來說,PBFT算法中使用 MAC 和公鑰簽名的具體場景是:

所有正常操作流程中使用 MAC 驗證消息;

視圖變更中的消息:view-change, new-view,以及出現錯誤時,使用公鑰簽名。這些場景的出現頻率相對較低,從而對算法的性能影響較小。

 


免責聲明!

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



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