1. 程式人生 > >共識網路BFT-SMaRt:理論與實踐

共識網路BFT-SMaRt:理論與實踐

目錄

  • BFT-SMaRt 簡介
  • 分散式計數器服務
    • 功能描述
    • 組網配置
    • 啟動節點
    • 常見問題
    • 計數服務
    • 容錯服務
  • BFT-SMaRt 理論
    • BFT-SMR 典型模式
    • SMR 狀態機複製
    • VP-Consensus
    • MOD-SMaRt 模組化
    • 優化措施
      • 日誌
      • 計算開銷
    • 結論
  • 後記
  • 更多文章請轉到一面千人的部落格園。

關鍵字:BFT-SMaRt,共識演算法,分散式網路,Java,區塊鏈,狀態機複製,MOD-SMaRt,VP-Consensus

BFT-SMaRt 簡介

官方定義:基於拜占庭容錯的狀態機複製方案的效能改善。從github的發行歷史來看,BFT-SMaRt專案最早於2015年4月釋出了beta版本。經歷了半年230個提交的迭代,當年12月BFT-SMaRt釋出了1.1beta版本。然後,直到2018年10月才推出了v1.2正式版。隨後,2019年2月、3月開始較活躍的發行,5月歸於平靜,直到現在(筆者日期:2020-01-02)。通過這個時間線,可以看出,BFT-SMaRt與比特幣的發展波動還是有一定的關聯。但無論怎樣,這是一個優秀的專案值得我們學習,目前也有很多區塊鏈團隊在使用。

分散式計數器服務

下面通過一個簡單的官方例項展開對BFT-SMaRt的學習。

功能描述

這是一個分散式計數器,它有4個節點,每個節點均可接收來自不同終端的計數請求。一個計數請求包含三個引數:

  1. 節點id
  2. 步進
  3. 迴圈次數

當某一個節點接收到一個終端的計數請求以後,它會將本地的計數字段的值改為請求的值,同時,其他3個節點的計數字段也會同步該結果。

在這個4節點的網路中,根據拜占庭容錯演算法 3f+1 = n,最多允許出現1個問題節點。

組網配置

config/hosts.config檔案是組網配置檔案,用於配置網路節點的訪問地址,包括節點id,ip及埠號。我們為便於學習,4個節點都部署在本機,只需要調整不同的埠號即可,4個節點共享同一份hosts.config檔案。

如果節點分佈在不同的機器,則每個節點均需要配置相同的hosts.config,用於描述同一個共識網路。

#server id, address and port (the ids from 0 to n-1 are the service replicas) 
0 127.0.0.1 11000 11001
1 127.0.0.1 11010 11011
2 127.0.0.1 11020 11021
3 127.0.0.1 11030 11031

預設情況下,不必修改。

啟動節點

節點的啟動是通過runscripts/smartrun.sh指令碼。

java -Djava.security.properties="./config/java.security" -Dlogback.configurationFile="./config/logback.xml" -cp bin/*:lib/* $@

該指令碼為java命令配置了bin/BFT-SMaRt.jar作為類執行檔案,還有日誌和安全的配置策略。BFT-SMaRt.jar是編譯整個BFT-SMaRt庫的jar包,所有的服務都整合在此,可在jvm虛機直接執行,熟悉Java的朋友應該很瞭解了,此處不再贅述。

回到專案根目錄,開啟4個連線會話,分別執行:

runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 0
runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 1
runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 2
runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 3

節點啟動成功,日誌會打印出節點id、ip及埠,節點總數、容錯數,超時、SSL/TLS傳輸協議等資訊。隨著節點的全部啟動,節點間會互相識別、同步,

lwb@lwbpc:~/work/bft-smart$ runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 
Use: java CounterServer <processId>
lwb@lwbpc:~/work/bft-smart$ runscripts/smartrun.sh bftsmart.demo.counter.CounterServer 3
-- Using view stored on disk
-- SSL/TLS handshake complete!, Id:0  ## CipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
-- SSL/TLS handshake complete!, Id:1  ## CipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
-- SSL/TLS handshake complete!, Id:2  ## CipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
-- ID = 3
-- N = 4
-- F = 1
-- Port (client <-> server) = 11030
-- Port (server <-> server) = 11031
-- requestTimeout = 2000
-- maxBatch = 1024
-- Binded replica to IP address 127.0.0.1
-- SSL/TLS enabled, protocol version: TLSv1.2
-- In current view: ID:0; F:1; Processes:0(/127.0.0.1:11000),1(/127.0.0.1:11010),2(/127.0.0.1:11020),3(/127.0.0.1:11030),
-- Retrieving State
-- Replica state is up to date
-- 
                ###################################
                    Ready to process operations    
                ###################################

當出現Ready to process operations時說明節點網路組建成功,服務可用,等待終端請求。4個節點在啟動時,後啟動的節點會顯示與前面的節點的安全連線資訊:SSL/TLS handshake complete!,這是建立連線,組網過程中的日誌。

常見問題

在啟動id為1的節點時(也就是第二個啟動),有可能報錯:

javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

異常資訊表示沒有合適的協議,cipher-suit(密碼套件,做SSL安全連線時使用)不可用。第二個節點啟動以後,根據hosts配置檔案對網路的描述,它會迅速與第一個節點建立安全連線,會使用到cipher-suit來建立SSL/TLS的加密連線。回到專案根目錄,進入config/system.config,這是BFT-SMaRt的全域性配置檔案。其中就包含了cipher-suit的啟用配置,可以找到:

system.ssltls.enabled_ciphers = TLS_ECDHE_ECDSA_WITH_NULL_SHA,
# With cipher (recommended).
#system.ssltls.enabled_ciphers = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,

將預設配置改為推薦配置,

#system.ssltls.enabled_ciphers = TLS_ECDHE_ECDSA_WITH_NULL_SHA,
# With cipher (recommended).
system.ssltls.enabled_ciphers = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,

重新啟動節點即可。

計數服務

開啟第5個連線會話作為終端,進入專案根目錄,輸入:

runscripts/smartrun.sh bftsmart.demo.counter.CounterClient 1 1 2

含義為:向id為1的節點發起請求,步進為1,執行兩次。得到的日誌輸出為:

Invocation 0, returned value: 1
Invocation 1, returned value: 2

節點的日誌輸出統一為:

-- Session Created, active clients=0
(1) Counter was incremented. Current value = 1
(2) Counter was incremented. Current value = 2

當前值為2,我們再次發起一個請求:

runscripts/smartrun.sh bftsmart.demo.counter.CounterClient 1 2 3

含義為:向id為1的節點發起請求,步進為2,執行3次。可推測出從2加3個2,最終結果為8,實際上日誌的顯示也是符合我們的推測的:

-- Session Created, active clients=0
(3) Counter was incremented. Current value = 4
(4) Counter was incremented. Current value = 6
(5) Counter was incremented. Current value = 8

BUG:clients有編號,第一個預設為0,當在本地啟動多個會話作為client發起請求時,會發生第二個client執行中止的情況,例如第一個client執行完請求以後並未退出執行緒,而此時第二個client發起一個執行次數為3的請求,那麼該客戶端日誌會卡在Invocation 0,而節點日誌會成功執行1次,剩餘2次未發生。此時退出一個client,仍舊可以正常服務。

容錯服務

我們來模擬一個節點斷線,然後再重新啟動。通過日誌分析,該節點再次接入網路以後,會主動請求其他節點,獲得之前的所有操作,然後本地依次全部執行,最終得到與其他節點相同的狀態值。

-- Retrieving State
-- Requesting state from other replicas
-- I just sent a request to the other replicas for the state up to CID 7
-- Received state. Will install it
-- Successfully installed proof for consensus 7
-- Last CID in state: 7
(1) Counter was incremented. Current value = 1
(2) Counter was incremented. Current value = 2
(3) Counter was incremented. Current value = 4
(4) Counter was incremented. Current value = 6
(5) Counter was incremented. Current value = 8
(6) Counter was incremented. Current value = 10
(7) Counter was incremented. Current value = 12
(8) Counter was incremented. Current value = 14
-- Setting last CID to 7
-- Current decided size: 0
-- All finished up to 7
-- 
                ###################
                    Ready to process operations    
                ###################
-- I updated the state!

通過這個日誌,可以非常清楚地看到狀態機複製的過程。

BFT-SMaRt 理論

BFT-SMaRt 是一個使用Java程式語言實現的分散式共識引擎,提升了模組化程度,更加可靠,同時提供了靈活的程式設計介面。字首BFT我們熟知,那麼SMaRt是什麼?可以看到大寫的部分SMR,其實是State Machine Replication,即狀態機複製的意思。那麼BFT-SMaRt認為它是BFT-SMR的改善方案,因此湊上了小寫字母a和t組成了smart。所以BFT-SMaRt可以解釋為:通過BFT實現SMR的一套改善解決方案

區塊鏈的分散式網路需要解決的拜占庭問題,在此就不多介紹了。在此之前,PBFT、POW、POS以及DPOS,這些拜占庭容錯類的演算法由於研究人員的學術或者效能需求,大多是由Go語言或C++寫成。這對於擁有廣大群眾基礎的Java從業者是不友好的,也是區塊鏈大規模商業化的阻力。因此,BFT-SMaRt最大的優勢或者特色就是使用了Java語言實現,同時可靠、模組化、介面靈活。

本章依據論文 From Byzantine Consensus to BFT State Machine Replication: A Latency-Optimal Transformation

BFT-SMR 典型模式

在BFT-SMaRt出現之前,大部分論文所提出的BFT實現SMR的典型模式,往往需要更多的步驟。我們知道PBFT本身是需要5步的,除去客戶端發起請求REQUEST與節點回復客戶端REPLY,中間還有三階段共識。PBFT是用來在聯盟鏈環境中達成正確共識的,一般來講都會為交易排序,達成統一順序的共識,但並沒有狀態校驗。理論上來講,當各個節點的交易順序是正確一致且完整的,那麼執行的結果即狀態值就應該是一致的。但是當系統脫離舒適區,來到了更加不可信的環境裡,需要具備狀態的檢驗作為double-check。而狀態機複製的概念,是一個相較區塊鏈更久遠的概念。叢集、分散式都會有負載以及同步的需求,多點承接請求,單點執行,多點再同步結果資料,這是一個耳熟能詳的過程。那麼BFT-SMR所研究的內容恰恰是以上的所有,因此它會需要更多的步驟,如下圖所示。

基於可靠的廣播通道,首先在SMR過程發生了三個步驟:訊息從客戶端發出並廣播到各個節點,節點間迴應,節點同步完成。然後再執行與PBFT相同的3PC共識,最後再加上一個訊息回覆REPLY。總共七個步驟。為了優化通訊的步驟,BFT-SMaRt提出了MOD-SMaRt模組化的概念,而實現BFT的共識被稱作Validated and Provable Consensus (VP-Consensus),即已驗證可證明的共識。
\[ BFTSMaRt=MODSMaRt+VPConsensus \]
VP-Consensus改善了現有的基於領導者驅動的共識演算法。

SMR 狀態機複製

在這個模型中,任意數量的客戶端程序向一組副本程序(分散式叢集)發出命令。這些副本實現一個有狀態的服務,例如一個賬戶的餘額。該服務在處理客戶端命令後更改其狀態,並向發出這些命令的客戶端傳送響應。該技術的目標是使每個副本上的狀態以保持一致的方式發展,從而使服務在每個副本上完整及準確地被複制。為了實現這種行為,需要滿足四個特性:

  1. 如果有兩個正確的副本r和r‘將操作o應用於狀態s,r和r’均獲得一個相同的狀態s‘。
  2. 任意兩個正確的副本r和r'均從狀態s0開始;
  3. 任意兩個正確的副本r和r’均執行相同的操作序列o0,…,oi;
  4. 來自正確客戶端的操作總是被執行。

前兩個要求可以在不使用任何分散式協議的情況下實現,但是接下來的兩個要求可以直接轉化為一個全順序廣播協議的實現——這相當於解決了共識問題。MOD-SMaRt滿足性質3和4,再加入一個VP-Consensus共識,被複制的服務將符合性質1和2。

VP-Consensus

VP-Consensus解釋為已驗證可證明共識。已驗證,指的是協議接收一個操作γ修改的一個值,那麼任何其他節點的值必須滿足修改,經受住驗證。可證明,即零知識證明,意味著協議生成一個加密證據Γ,可證明一個已採納的值v是正確的。VP-Consensus實現提供以下介面:

  1. VP-Propose(我,l,γ,v):在共識例項i中,提出了一個值v,,以及初始的leader(領導者)l和操作γ;
  2. VP-Decide(我,v,Γ):當值v在共識例項i中被採納時觸發;
  3. VP-Timeout(i, l):用於在共識例項i中觸發超時,並指定一個新的leader程序l。

關於這個介面,有三件重要的事情需要注意:

  1. VP-Consensus採用leader驅動的協議,類似於任何拜占庭Paxos共識。
  2. 該介面假設VP-Consensus實現可以處理超時來更改領導者(就像Raft那樣),並且在超時之後本地選擇新的領導者。
  3. 我們隱式地假定所有正確的流程將為該共識例項i呼叫VP-Propose,執行相同的操作γ。

VPConsensus具備以下特性:

  • 終止性:每一個正確的操作最終都會被有效執行;
  • 完整性:正確的操作不會執行兩次;
  • 一致性:執行兩次相同的操作,均會得到一致的結果。

此外,還需要另外兩個特性:

  • 外部有效性:如果在系統內一個正確的操作y修改了v,那麼外部執行γ(v)一定也是正確的;
  • 外部可證性:如果一些正確的操作修改了v,同時加密證據Γ在共識例項i中,那麼所有外部的正確操作均可以使用Γ來驗證:值v是我的正確修改。

MOD-SMaRt 模組化

上面介紹了VP-Consensus基本上與PBFT差不多,而MOD-SMaRt則是BFT-SMaRt較為核心的部分。該協議又分為三個子演算法:

  1. 客戶端操作,發起請求
  2. 正常階段(執行請求)
  3. 同步階段

MOD-SMaRt模組化首先的前提是建立在可靠已認證的點對點通道,外加VP-Consensus共識實現。MOD-SMaRt使用VP-Consensus在共識例項i中(建立交付訊息)執行一個正確的操作序列,這個操作序列也會在該共識例項中的其他副本中正確執行。MOD-SMaRt的一個副本架構如下圖。

在MOD-SMaRt第二個階段——正常階段中,一個正確的客戶端傳送請求到所有副本,一個共識例項會建立整個執行順序,執行操作,然後回覆給客戶端。如下圖所示:

接著,是第三個階段——同步階段。當第二次觸發訊息的超時時,將啟動此階段,啟動時同步執行VP-Consensus,如下圖所示,虛線部分對應VP-Consensus協議的訊息。

通過這個圖,可以清晰地觀察到MOD-SMaRt的每一個具體的步驟。

  • 首先,Client可以請求每個節點,這是SMR的步驟,VP-Consensus同時也在管理著4個節點通過超時來決定leader的工作。
  • STOP:節點間進行廣播,針對超時結束的節點徵求共識——是否成為leader。
  • STOP-DATA:節點達成一致,分別向leadert同步確認訊息。
  • SYNC:leader開始提出提案廣播,由client的訊息組成。
  • READ:再次進入VP-Consensus,節點間廣播,對提案的執行形成共識。
  • COLLECT:節點達成一致,分別向leader同步提案執行訊息。
  • PROPOSE:提案確定,形成決策,由leader廣播。

雖然沒有真的減少步驟,但是每個步驟都更加高效,兼顧了節點共識機制以及訊息狀態複製流程。

優化措施

對於MOD-SMaRt的實現,有兩種優化的措施。

日誌

第一個重要的優化措施與操作日誌的大小有關。在MOD-SMART中,日誌是可以無限增長的,這使得它不適用於實際系統。為了避免這種情況,我們建議使用檢查點checkpoint和狀態轉移state transfer。

①檢查點

檢查點將在每個副本中定期執行:在交付了一定數量的決策之後,副本將從應用程式請求狀態,將其儲存在記憶體或磁碟中,然後清除日誌。

②狀態轉移

用於副本發現自身日誌中最新決策與其他日誌不一致時所使用(網路不暢或系統異常)。首先主動向其他副本請求他們最新檢查點日誌中儲存的狀態。然後等待接收到來自不同副本的 f + 1 (正確的比錯誤的多一個即可)個狀態共識後,強制自己同步新狀態,並恢復執行。

計算開銷

第二個優化目標是避免在協議關鍵路徑中生成和驗證數字簽名的計算開銷。客戶端請求和VP-Consensus證明(以滿足外部可證明性)能夠使用MAC(訊息認證碼)代替數字簽名,就像在PBFT中做的那樣。然而,這種情況下的客戶端請求會導致一個不太健壯的狀態機實現,容易受到某些效能下降攻擊(例如DDOS)。如果我們使用基於BFT的VP-Consensus,並用到這種優化,MOD-SMaRt將匹配PBFT的訊息模式,同時有正確的領導者同步執行。因此需要相同數量的通訊步驟和密碼操作。這也正是在BFT-SMaRt所做的:一種使用了BFT優化MOD-SMART的實現。

結論

儘管存在一些優化改善BFT-SMR的工作,但它們都沒有將協議封裝在一個共識演算法中,只能是分片協作的。另一方面,所有已釋出的BFT實現的整個操作順序的廣播,比實際的BFT-SMR需要更多的通訊步驟。我們通過提供MOD-SMaRt(一種低延遲和彈性最優的BFT-SMR)來彌補這一缺陷,該演算法使用定義良好的共識演算法實現模組化。為了實現這種最優性,我們引入了經過驗證和可證明的共識抽象,它可以通過對現有的共識協議進行簡單修改來實現。

後記

下一篇,將升級一下難度,從原始碼角度來分析分散式計數器服務的實現方法,以及BFT-SMaRt自身的包括可靠通道、共識達成、執行緒分配、系統架構等內容。

更多文章請轉到一面千人的部落格園