本文主要介紹PBFT算法的垃圾回收、視圖變動機制及狀態機不肯定性問題的解決等。算法
1. 垃圾回收
本部分介紹PBFT算法的垃圾回收機制。安全
1.1 概述
本節介紹從本地日誌中刪除歷史消息的機制。服務器
對算法來講,爲了保證安全性,每一個副本節點須要保證以下兩點:
對於每一個請求來講,在被至少f+1個正常節點執行以前,全部相關的消息都必須記錄在消息日誌中;
同時,若是一條請求被執行,節點可以在視圖變動中向其餘節點證實這一點。網絡
此外,若是某個副本節點缺失的一些消息正好已經被全部正常節點刪除,則須要經過傳輸部分或所有的服務狀態來使節點狀態更新到最新。所以,節點須要某種方式來證實狀態的正確性。併發
若是每執行一次操做,都生成一個狀態證實,代價將會很大。所以能夠每執行必定數量的請求後生成一次狀態證實,例如:只要節點序號是某個值好比100的整數倍時,就生成一次,此時稱這個狀態爲檢查點。若是一個檢查點帶有相應的證實,咱們則稱其爲穩定的檢查點。oop
1.2 穩定檢查點的生成
如上所述,一個帶有證實的檢查點被稱爲穩定的檢查點,這種證實的生成過程以下:
一、副本節點i生成一個檢查點以後,會組裝檢查點消息,並全網廣播給其餘全部副本節點,檢查點消息格式以下:
<CHECKPOINT, n, d, i>,
這裏n指的是生成目前最新狀態的最後一條執行請求的序號,d是當前服務狀態的摘要。.net
二、每一個副本節點等待並收集 2f+1 個來自其它副本節點的檢查點消息(有可能包括本身的),這些消息有相同的序號 n 和摘要 d。這 2f+1 個檢查點消息就是該檢查點的正確性證實。日誌
一旦一個檢查點成爲穩定檢查點後,節點將從本地消息日誌中刪除全部序號小於或等於n的請求所對應的預準備、準備和確認消息。同時,會刪除全部更早的檢查點和對應的檢查點消息。
檢查點的生成協議能夠用來移動低水線 h 和高水線 H:
h的值就是最新穩定檢查點所對應的穩定消息序號;
高水線 H = h+k,這裏k要設置足夠大,至少要大於檢查點的生成周期,好比說:假如每隔100條請求生成檢查點,k就能夠取200。blog
2. 視圖變動
PBFT算法運行過程當中,若是主節點失效了,爲了保持系統的活性(liveness),就須要用到視圖變動協議。排序
2.1 視圖變動的觸發
因爲主節點失效時,客戶端最終會將請求發送到全部其餘副本節點。每一個節點收到客戶端請求後,若是該請求沒有執行過,副本節點判斷本身是否爲主節點,不是的話就會把請求轉發給主節點,同時啓動一個定時器(假如以前沒有啓動過的話)。
若是請求在定時器時間間隔內執行完,則節點會中止定時器(不過若是此時節點剛好在等待執行另一個請求,則會重啓定時器);不然,節點會嘗試觸發視圖的變動,具體過程以下節所示。
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 之間的請求,系統會從新運行三階段協議。只不過對於每個副本節點來講,若是當前確認的請求以前已經執行過的話,節點就再也不執行該請求。每條被執行的請求,其相關信息會被存儲在本地。節點根據這些信息肯定請求的執行狀況。
以上完成了對視圖變動的介紹。
2.3 視圖變動中節點的信息同步
視圖變動時,因爲 new-view 消息中並不包含原始的客戶端請求,所以副本節點可能缺失某條客戶端請求 m ,或者某個穩定的檢查點。
此時節點能夠從其餘副本節點同步缺失的信息。例如,假如節點 i 缺失某個穩定檢查點 s ,這個檢查點在 V 中能夠找到相應的證實,也就是 對應的 checkpoint 消息。因爲總共有 2f+1個這樣的消息,而錯誤節點最多 f個,所以至少有 f+1 個正常節點發送過這樣的消息。所以,能夠從這些正常節點獲取到對應的檢查點狀態。
對於副本複製服務的狀態來講,能夠經過生成不一樣的檢查點來劃分狀態。當節點須要同步狀態時,只需按檢查點來獲取便可。這能夠避免一次發送整個服務狀態。
3. 關於狀態機的不肯定性
PBFT算法基於狀態機副本複製服務,狀態機要求每一個節點的狀態必須是肯定性的。而大多數服務有時會有某種形式的不肯定性。例如,對於網絡文件系統而言,若是不基於狀態機副本複製的話,文件的最後修改時間這個屬性能夠設置爲服務器的本地時間。但若是是每一個副本節點獨自設置這個時間的話,就會致使各節點狀態的不一致。
所以,須要相應機制來確保各節點使用相同的值。通常狀況下,這個值不該該由客戶端來決定,由於客戶端擁有的信息並不徹底。例如,多個客戶端併發發送請求時,它們並不知曉其請求如何被排序。
能夠由主節點來選取這個值,具體有兩種方法:
1. 第一種方法適用於大多數服務,由主節點獨立選取非肯定的值。
主節點將該值和客戶端請求拼接在一塊兒,而後運行三階段協議,確保全部正常節點就請求和該值的序號達成一致。這能夠防止出現下列狀況:
失效的主節點故意向不一樣的副本節點發送不一樣的值,從而使各個節點上的狀態出現不一致。
對於這種方法來講,雖然全部正常節點使用相同的值,但這個由主節點發送的值多是錯誤的。這種狀況下,要求每一個副本節點必須可以基於其狀態來明確地判斷該值的正確性,以及如何處理可能的錯誤值。
2. 第二種方法是該值的選取由各副本節點一塊兒參與。這種方法要求在三階段協議基礎上額外增長一個階段:主節點收集各副本節點發過來的、可驗證來源的、共計 2f+1 個值,並把這些值和客戶端請求拼接在一塊兒,而後運行三階段協議。 以後,每一個副本節點基於這些值和各自的狀態進行肯定的計算,從而獲得
所需選取的值。這種計算能夠是相似於求中位數等。
相關閱讀:PBFT算法流程
本文結束,下篇文章將分享PBFT算法流程補充(二),關注咱們,第一時間獲取分享!