區塊鏈技術的起源與沿革(下篇):Hyperledger Fabric與分布式聯盟數據庫
原創【51CTO.com原創稿件】前言
說起當今最具代表性的數據通信技術,區塊鏈無疑在列。作為當下最受關注的次世代分布式系統,區塊鏈可謂眾說紛紜,莫衷一是。有人視之為引爆下一次互聯網技術革命的突破口,也有人稱其為投機工具,驚世騙局。本文旨在于盡可能懸置那些游離于技術層面之外的價值判斷,將視角重新移回到區塊鏈技術本身,完整回溯區塊鏈1.0到3.0的技術原理和設計理念之沿革,為讀者揭開籠罩在區塊鏈之上那層神秘的面紗。
第二章 Hyperledger Fabric與分布式聯盟數據庫
在上篇中已經詳細介紹了基于區塊鏈1.0設計的比特幣電子記賬系統。不設準入機制和POW算法使得比特幣兼具了網絡開放性和數據安全性。但是POW算法過高的算力開銷也極大限制了區塊鏈網絡的數據處理效率。區塊鏈技術不僅能夠應用于電子記賬,還可以廣泛應用于如金融,安保等對數據安全性敏感度較高的領域。在強大的技術需求驅動下,一項專為企業機構間信息共享而量身定做的區塊鏈項目應運而生,這就是Linux基金會旗下著名的Hyperledger Fabric項目。
一、Hyperledger Fabric的技術背景
Hyperledger Fabric是Linux基金會所主導的Hyperledger(超級賬本)項目之一。除Fabric外,Hyperledger生態下還包含了諸如Burrow,Sawtooth(以太坊拓展項目),Indy(數字身份平臺)等專門化項目。不同于比特幣網絡的公鏈設計,Hyperledger采用了內外網隔離和業務準入的聯盟鏈架構,在區塊鏈1.0網絡架構的基礎上進一步形成了節點角色的分化。這一設計規避了企業內部數據外泄的風險,同時也盡可能排除了潛在的安全隱患。
Hyperledger Fabric基于谷歌的gRPC框架開發,實現了網絡內任意節點的對等通信。同時使用Docker容器技術來托管構成基本交互邏輯的智能合約。簡而言之,Hyperledger Fabric是專門為企業和機構設計的通用型業務系統。
二、Hyperledger Fabric的數據結構
1. Hyperledger Fabric的區塊鏈結構
圖十四:Hyperledger Fabric的區塊鏈結構
Hyperledger Fabric的區塊鏈結構與比特幣大體相同,每個區塊都由區塊頭和區塊體組成,并通過父區塊哈希編碼構成唯一鏈接。不過Hyperledger Fabric在區塊鏈1.0的基礎上進一步加入了一層狀態緩存設計,用以提高讀寫性能。
Hyperledger Fabric和比特幣網絡一樣,本質上是一個分布式賬本(Hyperledger Fabric的賬本交互邏輯可以由使用者根據自身業務定制,在數據存儲的靈活性上要優于區塊鏈1.0系統)。在底層結構中都是通過鍵值對的方式來存儲數據。而區塊鏈為了實現數據的時間可回溯性和數據防篡改機制,在鏈中并不保存數據的狀態,而只保存對數據的變更。這就使得對某條數據的狀態查詢需要進行全鏈遍歷,其查詢性能很難滿足一些企業級業務的性能需求,因此Hyperledger Fabric引入了“世界狀態(World State)”這一概念。當區塊中保存某一條記錄時,會同步更新對應Key的世界狀態。當需要查詢某個鍵值時,只需要查詢對應的世界狀態即可,而無需進行全鏈遍歷。
需要強調的是,世界狀態是脫鏈保存在LevelDB/CouchDB結構中的,是一種鏈外附加緩存機制,世界狀態的丟失并不會對區塊鏈中的數據產生影響。
2. Hyperledger Fabric的賬本結構
當網絡中的排序節點打包好最新區塊分發到每個記賬節點后,記賬節點會對本地的區塊鏈數據進行更新,其賬本存儲結構如下圖所示:
圖十五:Hyperledger Fabric的賬本結構
首先每個記賬節點都保存了所有的歷史區塊信息,區塊以文件系統的形式存儲,多個區塊以集合形式存儲在一個文件塊當中。區塊鏈通過文件編號,區塊編號,偏移量來實現對某個歷史區塊的快速索引。
區塊鏈數據也是記賬節點中唯一的持久化數據,永久保存且不可更改。某個區塊硬編碼為64M大小,以六位編碼區分,理論單鏈最多可以容納64*1000000M的數據量。當一個新的區塊請求寫入時,記賬節點首先會將新的區塊添加到本地區塊鏈中,然后將數據同步給狀態數據庫(世界狀態即目前數據的終態,也就是原始狀態+區塊鏈中所有交易操作的疊加后的最終狀態)。
當每次節點啟動時,首先會校驗區塊鏈,世界狀態,鍵歷史索引中的數據是否一致,若不一致,則可以通過區塊鏈信息重構狀態數據庫。當然如果從創世區塊開始重構世界狀態性能開銷往往很大,因此Hyperledger Fabric加入了額外的歷史狀態模塊,這一模塊記錄了對世界狀態中每一個鍵值對的操作(交易請求)的編碼,當重構某一鍵值對時只需要從區塊鏈中篩選出相應的交易請求執行即可,無需遍歷整個區塊鏈)。
3. Hyperledger Fabric的讀寫集機制
讀寫集是Hyperledger Fabric進行數據更新時所依賴的核心技術,當背書節點進行交易模擬時會對交易請求進行驗證。讀寫集分為讀集(讀已提交的狀態值)和寫集(將要更新的狀態鍵值對,狀態鍵值對刪除標記,若對同一鍵值對進行多次更新則以最后一次為準)。執行交易驗證時,對于某個更新操作,只有當讀集版本號=世界狀態版本號時,才會執行寫集。寫集每更新一個鍵值對,都會同時更新這一鍵值對的版本號。這一設計的目的在于保障同一區塊中的多筆交易不會對世界狀態產生重復操作(類似于Redis的樂觀鎖機制)。
例如世界狀態中存在某一鍵值對(A,100,V1),此時兩筆時間相近的交易請求被打包進了同一個區塊中執行:
請求一:讀出A值為100后執行扣減50操作;
請求二:讀出A值為100后執行扣減20操作;
當請求一執行后世界狀態更新為(A,50,V2),此時如果請求二執行,則仍然按照之前讀到的(A,100,V1)世界狀態進行操作,操作后世界狀態更新為(A,80,V2),繼而抹除了請求一的操作,因此進行版本驗證的目的在于避免在高并發情況下出現數據丟失的情形。
三、實用拜占庭容錯算法(Practical Byzantine Fault Tolerance)
1.PBFT的基礎模型
在前文中我們已經介紹了分布式系統必然面臨的數據一致性問題——拜占庭將軍問題。區塊鏈1.0的網絡架構主要通過POW算法實現全網共識,以強制記賬節點用物理開銷來換取記賬權的方式規避作弊行為。但是POW算法的解謎設計也造成了很大的資源浪費,大量的算力被浪費在了沒有實質意義的數字謎題上。而Hyperledger Fabric作為聯盟鏈,其更偏重于滿足企業的分布式數據存儲和企業間的數據共享需求,因此性能成為了網絡架構設計層面不得不考慮的問題。Hyperledger Fabric在區塊鏈1.0的基礎上引入了網絡準入機制,只有賦權節點才能訪問區塊鏈中的數據,節點數目要遠遠小于公鏈系統,POW已經不再適合聯盟鏈系統的設計開發。因此,Hyperledger Fabric采用了成本開銷更低,性能更高的一種共識算法——“實用拜占庭容錯算法(PBFT)”。
由萊斯利·蘭伯特所提出的BFT算法僅僅只是在理論上證明了拜占庭容錯的可行性,但是在實際的分布式系統設計中,由于網絡阻滯等原因,BFT算法幾乎無法被應用。因此在BFT的基礎上,卡斯特羅,米格爾,芭芭拉•利斯科夫等三位計算機科學家進一步提出了能夠實際應用的PBFT算法。
PBFT算法首先區分了分布式系統的三種基本模型:
強同步性(Synchrony)模型,任意一個節點發出的消息都能在確定的時間周期內送達目標節點。
強異步性(Asynchrony)模型,任意一個節點發出的消息都未必能到達目標節點。
弱同步性(Partial Synchrony)模型,任意一個節點發出的消息在可能的延遲范圍內最終會送達目標節點。
強同步性與強異步性模型所設定的情況都過于極端,在實際的分布式系統中情況更加接近弱同步性模型。PBFT算法基于弱同步性模型設計,即消息可能延遲,但不會無限延遲。
假設一個分布式網絡中故障/惡意節點為F個,總節點數為N個,在弱同步性模型中,PBFT需要確保兩點:
當某個節點收到一條消息時,考慮到最多可能有F個節點保持靜默,因此當收到N-F條消息時就要開始驗證,而且N-F條消息中至少要有多于F條消息一致才能完成容錯判定。因此N和F需要滿足:
N - F > F
此外N-F條消息中還有可能包含F個來自惡意節點的假消息,因此真消息的數目至少要多于F條才可以完成容錯判定,故而N和F需要滿足:
N - F - F > F
綜上有:
故當惡意/故障節點不超過總結點數1/3的情況下,PBFT算法能夠實現全局一致性。
2.PBFT的網絡拓撲模型
圖十六:PBFT的網絡拓撲模型
PBFT實現的分布式網絡需要滿足兩個條件:
- 每個節點具有相同的起始狀態;
- 在相同的狀態下,同一操作產生的結果相同。
在一個PBFT算法實現的分布式網絡中,一組節點中選取一個節點作為主節點(Primary),其它節點作為備份節點(Backup)。選取某個節點擔任主節點的事態稱為系統的一個視圖(View)。當主節點故障時將重新選取主節點,主節點發生變化時視為系統的視圖發生了一次更新。假設在View1視圖下網絡對某條消息m的排序n達成一致,為Order⟨view1,m,n⟩,那么當視圖更新后對m的排序仍然為Order⟨view2,m,n⟩,即視圖轉換前后消息排序不會發生改變。
3.PBFT的消息處理流程
圖十七:PBFT的消息處理流程
PBFT的消息處理流程大體上分為請求(Request),預處理(Pre-prepare),準備(Prepare),提交(Commit),響應(Reply)五個階段。我們通過一個四節點,一個客戶端的簡單網絡模型來對PBFT的信息傳輸校驗流程加以說明:
在該網絡模型中,Primary節點和Backup1,Backup2節點為正常節點,Backup3節點發生故障無法做出響應,符合N>3F要求。
首先在Request階段,Client向Primary發出一條請求,消息格式為:
其中o 表示操作請求內容,t表示當前時間戳,c表示Client節點。
當Primary收到該消息并驗證后,進入Pre-prepare階段,Primary給予消息m一個序號n,向Backup1,Backup2,Backup3廣播預處理消息,消息格式為: 其中v表示當前的系統視圖,n為消息排序,m為消息內容,d為消息m的哈希值。
當Backup1,Backup2節點接收到Primary節點的消息后,首先會驗證系統視圖是否發生了更新,消息簽名是否合法,排序n是否處于當前視圖高低水位之間(為了保證n不出現極大極小值,同一視圖下系統會對n的取值域進行限制,使n∈(h,H)),以及是否收到過其它排序為n的消息(確保不同的消息不會獲得相同的排序)。驗證通過后,進入PREPARE階段,該節點會向其它節點(包括Primary節點)發送一條準備消息并將該消息存入本地日志中,消息格式為: 其中i表示當前節點。
當其他節點收到該消息后,會進行如下校驗并將該消息存入本地日志:
第一步,校驗本地日志中是否存在消息m。
第二步,校驗本地日志中是否存在m的PRE-PREPARE消息。
第三步,校驗本地日志中是否存在至少2F個關于m的PREPARE消息。
若校驗通過,則稱本節點對消息m達成了PREPARED狀態。此時該節點會向其它節點廣播,消息格式為:
當其它節點收到該條COMMIT消息時,會進行如下校驗并將該消息存入本地日志:
第一步,檢驗本節點是否對消息m達成PREPARED狀態。
第二步,校驗本地日志中是否至少有2F條來自其它節點的關于m的COMMIT消息。
若校驗通過,則說明對m的排序已經達成了全局一致,此時稱該節點對消息m達成了COMMITTED-LOCAL(m,v,n,i)狀態,可以直接返回給Client,消息格式為: 其中r和t相同,用于時間校驗,當Client收到F+1個一致的REPLY消息時,共識流程結束。
圖十八:節點本地日志庫狀態轉移圖
為了更直觀地理解這一流程,我們作出每個節點本地日志庫的狀態轉移圖。其中藍色標識的消息為節點自己產生,綠色標識的消息來自其它節點。
首先Client發出REQUEST消息,該消息被保存在Primary的日志庫中。然后Primary發送PRE-PREPARE消息給Backup1,Backup2,Backup3。Backup1,Backup2分別在日志庫中保存該條PRE-PREPARE消息。然后向其它節點發送PREPARE消息。
Primary收到來自Backup1,Backup2的兩條PREPARE消息并保存在日志庫中。而Backup1,Backup2除了一條自己產生的PREPARE消息外,還收到一條其它節點的PREPARE消息。此時三個正常節點日志庫均滿足:
- 存在消息m的日志;
- 存在消息m的PRE-PREPARE日志;
- 存在消息m的2F個PREPARE日志。
此時三個節點均達成了關于m的PREPARED狀態,繼而向其它節點發送COMMIT消息。
由圖可見,三個正常節點除了自身產生的一條COMMIT消息外,均收到了2條來自其它節點的COMMIT消息,均達成COMMITTED狀態,返回REPLY消息給客戶端,完成共識流程。
4.PBFT的垃圾回收機制
PBFT算法對信息的階段性校驗需要用到節點的日志庫,隨著信息的增加,日志庫中的冗余數據也會越來越多,因此PBFT會通過定期的垃圾回收來釋放內存空間。PBFT的垃圾回收通過Checkpoint機制來完成。Checkpoint點的設置為某個常數K的整數倍。假設當前消息排序值n取值的高低水位為h到H之間,當被排序的消息數超過H時,節點便會發送CHECKPOINT消息,消息格式為:
當某個節點收到2F+1條CHECKPOINT消息后,便會將高低水位重新置為n∈(H,H+K),并刪除排序值小于H的消息日志,釋放內存空間。
5.PBFT的視圖更新機制
因為PBFT通過主節點完成對消息的排序,因此就存在主節點故障的風險。對此PBFT設計了一套對應的視圖更新機制來保證主節點故障的情況下整個系統的可用性。
當某個節點i監測到主節點響應超時,便進入視圖更新流程,并發送一條VIEWCHANGE消息,消息格式為:
其中n為最近一個Checkpoint的序號,C為對應的2F+1個CHECKPOINT消息集合。P為一個達成PREPARED狀態的消息集合:
Pm表示序號大于n且達成PREPARED狀態的消息m的至少1個PRE-PREPARE消息和至少2F個PREPARE消息的集合(也就是使消息m達成PREPARED狀態的所有預處理消息和準備消息的總集)。
當新的主節點Primaryv+1收到2F個有效的VIEWCHANGE消息后,會廣播一條新視圖消息,消息格式為:
其中V是Primaryv+1收到的所有VIEWCHANGE消息的集合,O為以新視圖構造的PRE-PREPARE消息的集合,至此視圖更新流程結束。這一機制有效確保了系統在視圖更新前后達成PREPARED狀態的消息排序不變。
四、Hyperledger Fabric的網絡拓撲結構與共識機制
Hyperledger Fabric使用PBFT作為其共識算法的底層實現。對于分布式系統而言,數據一致性策略可分為強一致性策略和最終一致性策略。所謂強一致性策略是指系統能夠實現在極端條件下的數據一致性,其涉及到復雜的數據交互,且對系統壓力較大,并不適合商業級數據存儲。因此Hyperledger Fabric采用了最終一致性策略,所謂最終一致性是指系統可以容忍在短時間內不同節點數據不一致的情形,整個區塊鏈網絡只需要保證在一定時間周期內達成一致即可。
圖十九:Hyperledger Fabric的網絡拓撲結構
如圖所示,Hyperledger Fabric采用多中心的網絡架構模式,由獨立的排序節點對來自不同終端的交易請求進行規整處理,封裝成區塊后再下發到整個區塊鏈網絡。
Hyperledger Fabric網絡下主要有四種類型的節點:
- Client節點(客戶端節點),這一節點主要用于提供應用訪問區塊鏈網絡的入口,負責系統與區塊鏈之間的數據交互。
- Peer節點,包含了Anchor節點(錨節點),Endorser節點(背書節點)和Committer節點(記賬節點)。其中錨節點每個組織中至多只有一個,負責和其他組織以及order節點交互,組織網絡中的非錨節點不直接參與和外部網絡的信息交換。背書節點負責模擬執行來自用戶的交易請求,并對請求進行驗證和簽名。記賬節點負責保存區塊鏈信息,更新世界狀態等。需要強調的是這三種角色之間并非互斥關系,一個Peer節點可能同時兼有背書節點,記賬節點等多種角色,而且所有的Peer節點都是記賬節點。
- Order節點,共識機制的核心節點,負責對來自用戶的交易請求進行排序,打包成區塊后分發給其它組織的錨節點。
- CA節點(鑒權節點),非必要節點,主要負責證書的頒發,身份驗證及用戶鑒權等。也可通過第三方證書鑒權機構實現。
就Hyperledger Fabric的網絡拓撲結構而言,其并不同于如比特幣,以太坊等常見公鏈的網狀拓撲結構,而是更接近于具備一定層級關系的樹狀拓撲結構(就此而言,Hyperledger Fabric并非是一個去中心網絡,而是一個多中心網絡)。
不同的組織分屬于不同的網域,每個組織結構下只暴露一個錨節點作為與其它組織交互的接口。這一設計主要是出于部分企業的數據安全性考慮。很多企業核心數據往往不便于直接暴露在公網中,內外網隔離的設計可以充分確保敏感數據的安全性。
除了不同的組織外,區塊鏈網絡中還存在由Order節點組成的排序網絡,Order節點有Solo和Kafka兩種運行模式。Solo模式由單個Order節點提供排序服務,往往只是用于網絡測試和節點數較少的場景。商業應用中一般采用Kafka模式,Order節點將接收到的交易請求發送給Kafka集群,由Kafka集群排序后再返回給Order節點,這一設計大大提升了Order集群的排序分發效率。
圖二十:Hyperledger Fabric的多通道排序機制
在企業應用場景中可能存在一個區塊鏈網絡需要承接多種業務的情形,因此Hyperledger Fabric采用了多通道設計。所謂通道指的是一個封閉的業務群,一個Hyperledger Fabric網絡中可能存在多個業務群處理不同的業務,彼此之間在邏輯和物理上均相互隔離。有幾個業務群就會存在幾條不同的區塊鏈,每個節點都只會保存自己加入的通道的區塊鏈數據,進而杜絕了多業務交叉場景下數據外泄的風險。而排序節點也會根據通道的不同將交易請求分發給不同的Kafka隊列,實現業務間的鏈級隔離。
Hyperledger Fabric網絡中一個完整的交易流程為:
客戶端首先提交交易提案發送給背書節點(至少兩個,具體可在背書策略中設置,用戶可指定要使用的背書節點),背書節點收到交易提案后啟動鏈碼(運行在一個隔離的安全容器中,無法被人為干預)模擬交易(僅僅是模擬,并不會更新到區塊鏈網絡中)。鑒權驗證通過后背書節點會添加數字簽名并返回給客戶端(理論上多個背書節點返回的執行結果應當一致)??蛻舳藢⒑灻蟮慕灰渍埱蟀l送給Order節點,Order節點進行排序后打包成區塊分發給各組織錨節點。錨節點分發給組織內記賬節點,記賬節點驗證完成后將最新的區塊添加到本地區塊鏈中,并更新世界狀態。
五、智能合約
圖二十一:發起交易和智能合約調用流程
智能合約(鏈碼)是Hyperledger Fabric用于應用和區塊鏈網絡之間交互的媒介。鏈碼部署在獨立且隔離的Docker容器中,無法被外界干預和篡改,通過gRPC與背書節點通信。背書節點將交易請求發送給鏈碼容器后,鏈碼容器返回給背書節點該筆交易的執行結果。
智能合約類似于應用系統中的對外接口,而交易就是對接口的一次調用。鏈碼中對外接口只提供兩個方法,Init方法和Invoke方法。Init方法只會在區塊鏈網絡啟動時在任意一個節點執行一次,Invoke方法則用于應用和區塊鏈網絡之間具體的交互。
鏈碼存在五個生命周期,打包(鏈碼的編譯),安裝(上傳到背書節點),實例化(執行Init方法),升級(鏈碼中的功能拓展和Bug修復),交互(應用調用)。
企業用戶可以根據自身業務場景編寫不同功能的智能合約來實現應用和區塊鏈網絡之間的數據交互。
六、Hyperledger Fabric的業務應用
Hyperledger Fabric是一套專門為機構和企業設計的通用型業務方案。其相比于區塊鏈1.0和2.0,可以靈活的根據用戶業務進行定制。而模塊化和插件式的服務模式也大大降低了用戶的組網成本。非常適用于金融,支付等高敏感性業務場景。而Hyperledger Fabric底層的鍵值對存儲結構也具有很強的擴展性。傳統數據庫能夠存儲的數據,理論上Hyperledger Fabric都可以存儲。其多通道設計可以實現物理級別的業務解耦,多種業務都可以無干擾地掛載在同一區塊鏈網絡下。實現資源復用的同時又避免了機構之間業務交叉產生的數據外泄風險。
Hyperledger Fabric的另一大優勢在于用戶可以根據自身業務編寫智能合約,定制應用系統和區塊鏈網絡的數據交互模式。這就為復雜業務場景和區塊鏈技術的縫合提供了便利,使得“區塊鏈+”得以真正進入企業級應用之中。
結語
區塊鏈技術問世以來,十數年間歷經三次迭代,其間或譽或諑,不絕于耳。唯有撥開籠罩在區塊鏈上的那層神秘面紗,深究其技術原理,方能得見其真容。單純作為一種技術而言,區塊鏈本身是價值無涉的。工具能釋放出怎樣的社會價值,終究取決于其使用者。我們也許驚嘆于設計者的曠世奇思,但絕無必要為其賦予太多超脫于技術之外的神秘色彩。區塊鏈也許是通往未來的一個入口,但任何技術奇點的引爆都并非來自于某個單點技術突破,而是醞釀于厚積薄發的逐步嬗變。勤懇與踏實才是推動社會進步的最終驅力,在技術瞬息萬變,發展一日千里的當下,我們更當持守此心。
參考文獻
[1] Satoshi Nakamoto: Bitcoin:A Peer-to-Peer Electronic Cash System[EB/OL]
[2] Castro,Miguel,Barbara Liskov: Practical Byzantine fault tolerance.OSDI.Vol.99.1999
[3] Kwon,Jae: Tendermint:Consensus without mining.Draft v.0.6,fall(2014)
作者簡介:
王翔,畢業于安徽大學2018屆電子信息工程專業,現就職于某知名世界五百強互聯網企業。致力于服務端系統的架構設計,多活部署,性能優化,業務開發等工作。
【51CTO原創稿件,合作站點轉載請注明原文作者和出處為51CTO.com】