PBFT之三階段提交

PBFT之三階段提交

1 前言

  Raft保證當複製狀態機數量爲3f+1時, 最多能夠容許f個狀態機虛假。
  一個view中只有一個primary 其餘爲副本。
  視圖更改說明primary崩潰或失敗。算法

2 算法流程

  1. 客戶端發送請求到primary調用服務操做
  2. primary廣播請求到全部節點
  3. 節點執行請求並返回響應到客戶端
  4. 客戶端等待從不一樣的節點發送的結果相同的f+1個響應。響應內容爲操做的結果。

算法對節點的要求:安全

  1. 節點必須是肯定性的(給予一系列參數執行操做必須產生相同的結果)。
  2. 節點必須以相同的狀態啓動

2.1 客戶端c

  客戶端經過發送消息 <REQUEST,o,t,c>primary請求狀態機執行操做o
  t:時間戳用於確保該操做只執行一次,而且全部的請求都按照時間戳前後排序。
  由節點發送到客戶端的消息包括(當前視圖號v,容許客戶端去跟蹤視圖發現當前的primary).優化

  節點直接發送響應到客戶端,響應內容包括<REPLY,v,t,c,i,r>.
v:當前視圖號。
t:響應請求的時間戳。
i:節點ID
r:執行操做獲得的結果。日誌

  • 客戶端等待由不一樣的節點返回的具備相同的tr的響應消息。
  • 若是客戶端沒有接收到足夠的響應,將廣播請求到全部節點。若是請求已經被處理,節點只簡單地從新發送響應。
  • 節點保留髮送到每個客戶端的最新的響應消息。
  • 不然,若是節點不是primary,將會重定向請求到primary,若是primary沒有多播請求到集羣,將會被懷疑是錯誤節點。若是有足夠多的節點懷疑則會發生視圖更新。

3 正常狀況下三階段提交

  每個節點的狀態包括服務的狀態。消息日誌包括節點被接受的信息,以及節點當前的視圖。
  當primary接受到客戶端的請求m,將開始三個階段的協議進行自動多播請求到節點。
  除非消息的數量超出協議中給定的最大消息數量不然primary當即開始該三階段協議。若是消息超過最大消息數,將會將請求放置緩衝區。code

  三階段分爲pre-prepare,prepare,commitblog

  • pre-prepareprepare階段用於對在同一視圖中發送的請求徹底排序,即便提出請求排序的primary爲虛假節點也是如此。
  • preparecommit階段用於確保在視圖之間對提交的請求進行徹底排序

3.1 PRE-PREPARE階段

  在pre-prepare階段,primary定義了一個序列號n,到請求消息中。多播一個pre-prepare消息並聯合消息m到全部節點。並將該消息添加到日誌中。該消息內容爲 <<PRE-PREPARE,v,n,d>_s,m> (_s表明簽名)這裏的v代表被髮送的消息處於的視圖。m是客戶端的請求消息。dm的摘要。
  爲了保持消息較小。請求沒有包括在pre-prepare消息中。這是很重要的由於pre-prepare消息用於做爲該請求定義的序列號n在視圖v中的證實。另外,它將協議與協議徹底分離,以將請求傳輸到節點;容許咱們爲協議消息使用針對小消息優化的傳輸,對於大型請求針對大消息使用優化的傳輸。
  節點接收到提供的pre-prepare消息後:排序

  • 請求中的簽名和pre-prepare消息是有效的,而且dm的摘要。
  • 視圖v是有效的。
  • 在視圖v中沒有接收到其餘的具備序列號n的包含不一樣摘要的消息。
  • pre-prepare消息中的序列號在低的閾值h與高閾值H之間。

  最後一個條件用於阻止錯誤的primary爲了耗盡序列號空間而選擇一個很是大的值。it

  若是節點i接受了 <<PRE-PREPARE,v,n,d>_s,m> 消息。節點將會進入prepare階段,並多播 <PREPARE,v,n,d,i>_s 消息到全部其餘的節點,並將該消息添加到它的日誌中。不然將什麼也不作。集羣

3.2 PREPARE階段

  節點(包括primary)接收了prepare消息:變量

  • 簽名是有效的
  • 視圖號與節點當前視圖相同
  • 序列號在hH之間

  並添加他們到本身的日誌中。

  只有當節點i已將如下消息添加到它的日誌:

  • 請求m
  • 在視圖v中具備序列號n且是請求mpre-prepare消息(來自不一樣節點2f個)

  而且節點經過檢查prepare消息與pre-prepare消息具備相同的視圖,序列號和簽名,才認爲prepared (m,v,n,i) 消息爲有效的。

  算法的pre-prepareprepare階段保證誠實節點贊成視圖中請求的總順序。更準確的,確保如下的變量:

  • 對於任意的誠實節點j(包括i=j),若是prepared (m,v,n,i) 消息是有效的,那麼prepared (m’,v,n,j) 消息是無效的。而且任何D(m') 不等於D(m).
  • 由於prepared (m,v,n,i) 消息和 R=3f+1代表至少有f+1個誠實節點在視圖v中發送了序列號爲npre-prepare消息或者是prepare消息。
  • 所以,對於prepared (m’,v,n,j) 消息若是是有效的,那麼須要至少一個誠實節點必須發送兩個衝突的prepare消息(或者是視圖爲vprimary發送pre-prepare消息),兩個prepare消息具備相同的視圖和序列號可是具備不一樣的摘要信息。可是這是不可能的由於節點不是虛假節點。
  • 最後,關於消息摘要強度的假設可確保m不等於 m' 而且 D(m) 等於 D(m') 是不可能的。

3.3 COMMIT階段

  當prepared (m,v,n,i) 消息爲有效的那麼節點i多播 <COMMIT,v,n,D(m),i>_s 消息到其餘節點.這個過程爲commit階段。節點接收commit消息並添加該信息到日誌中。

  • 簽名是有效的
  • 消息中的視圖號等於節點當前視圖號
  • 序列號在hH之間

  若是而且只有當對於全部在f+1誠實節點中的節點iprepared (m,v,n,i) 消息都是有效的,那麼committed (m,v,n,i) 消息則是有效的。
  若是而且只有當節點i從不一樣的節點接收到2f+1commit消息(可能包括本身),而且與請求mpre-prepare消息匹配(具備相同的視圖,序列號和摘要)。則committed-local (m,v,n,i) 消息是有效的。

commit階段確保如下變量:

  • 若是對於一些誠實節點icommitted-local (m,v,n,i) 消息是有效的。那麼committed(m,v,n) 消息是有效的。
  • 誠實節點贊成本地提交的請求的序列號,即便它們在每一個節點上以不一樣的視圖提交,進一步,在誠實節點上本地提交的任何請求最終都將在1個或多個誠實節點上提交。

  每個節點i在當committed-local(m,v,n,i) 消息是有效的,而且i的狀態反應了在全部請求中該請求的序列號是最小的狀況下將會執行該操做。確保了全部誠實節點能夠以相同的順序執行請求,保證了安全性。在執行完請求操做後,節點將返回一個響應到客戶端。
  當請求的時間戳小於最後一次回覆的時間戳時節點拋棄該請求。保證只執行一次。

  不依賴消息順序交付。所以可能節點亂序提交請求。這是無所謂的,由於節點保持了pre-prepare,prepare,和commit消息日誌一直到該請求被執行。

圖展現了該算法的以一種正常的例子(沒有primary虛假)的操做。節點0爲primary,節點3爲虛假節點。C爲客戶端.
圖

相關文章
相關標籤/搜索