Fabric架構(gòu)

Fabric網(wǎng)絡(luò)

Fabric模塊

Fabric交易流
根據(jù)Hyperledger Fabric 1.0架構(gòu),F(xiàn)abric交易的整個生命周期可以分為7個階段。我們可以從一個簡單的例子分析下Fabric交易的7個階段,然后讀者可以清晰的理解每個環(huán)節(jié),每個處理過程,這可以幫助開發(fā)人員理解Fabric的架構(gòu)體系,只有深刻理解了Fabric的架構(gòu)設(shè)計原理,在開發(fā)過程中遇到問題才能快速解決。
如下圖反應(yīng)了交易的整個生命周期以及交易于賬本的交互。

第一階段
在交易的第一階段,客戶端應(yīng)用發(fā)起智能合約A的一個交易請求給背書節(jié)點E0。智能合約A配置的背書策略要求只需要E0,E1和E2簽名。其他節(jié)點不包含在策略的要求中,因此可以不簽名。注意圖中的紅色和藍(lán)色小矩形塊分別代表不同的子鏈或者叫通道,這個通道是1.0架構(gòu)引入的新概念,用來實現(xiàn)各條業(yè)務(wù)鏈的數(shù)據(jù)隔離,保護交易的隱私性,避免像比特幣那樣的交易對所有人都公開。

如圖所示,這里說明一下,圖中的C代表共識網(wǎng)絡(luò)(Consensus Network),黃色的圓角矩形表示在peer上部署的智能合約。如E0,E1,E2上部署了A,B兩個智能合約,E3上部署了A,D兩個智能合約,而E4,E5上部署了Y,Z兩個智能合約。
第二階段
背書節(jié)點E0使用 MSP(MSP=Member Service Provider)驗證簽名,判斷是否客戶端應(yīng)用被正確授權(quán)可以執(zhí)行發(fā)起交易請求。背書節(jié)點獲取交易請求中的參數(shù)(鏈代碼)作為輸入?yún)?shù),然后E0會與交易對應(yīng)ChainCode所屬的docker實例通信,并為其提供模擬執(zhí)行的State Database的讀寫集,也就是說ChainCode會執(zhí)行完智能合約中的業(yè)務(wù)邏輯,但是并不會在stub.PutState的時候?qū)憯?shù)據(jù)庫,ChainCode所屬的docker實例執(zhí)行完ChainCode后產(chǎn)生交易執(zhí)行結(jié)果,然后將執(zhí)行結(jié)構(gòu)返回給E0。這個執(zhí)行結(jié)果包括下列數(shù)據(jù):響應(yīng)值,讀集合和寫集合。不過,這個時候,并不會更新賬本。這些值的集合,連同背書節(jié)點的簽名和一個YES/NO 的陳述一起放到 proposal response 中返回給客戶端應(yīng)用(圖中的Client App)。

第三階段
客戶端應(yīng)用驗證背書節(jié)點簽名,然后繼續(xù)發(fā)送背書請求給E1和E2,過程跟與E0的交互時一樣。

第四階段
背書節(jié)點E1和E2發(fā)送背書處理結(jié)果給客戶端應(yīng)用??蛻舳藨?yīng)用收集完所有背書節(jié)點的簽名后,檢查是否指定的背書策略已經(jīng)滿足。根據(jù) Fabric 的架構(gòu)設(shè)計,即使應(yīng)用選擇不檢查交易的背書反饋,或者繼續(xù)發(fā)送一個沒有經(jīng)過背書處理的交易,在commit交易的驗證階段,這個背書策略仍然會被peer 強制執(zhí)行。

第五階段
客戶端應(yīng)用將交易和響應(yīng)信息封裝到一個事務(wù)消息(transaction message)中,然后廣
播到共識網(wǎng)絡(luò)(這里的共識網(wǎng)絡(luò)又稱為排序服務(wù)Ordering Service,后續(xù)統(tǒng)一稱為共識網(wǎng)絡(luò))。交易中包含讀寫集,背書節(jié)點簽名和通道 ID。
共識網(wǎng)絡(luò)節(jié)點不會關(guān)注交易細(xì)節(jié)和交易消息的具體內(nèi)容,只是簡單地從網(wǎng)絡(luò)中接收來自所有通道的交易,然后按通道按時間順序排序,處理的結(jié)果是一個Batch的交易,也就是一個區(qū)塊,這個區(qū)塊的產(chǎn)生有兩種情況,一種情況是區(qū)塊中的交易很多,區(qū)塊的大小達(dá)到了配置文件中配置的大小,而另一種情況是區(qū)塊中的交易很少,沒有達(dá)到配置的大小,那么共識網(wǎng)絡(luò)節(jié)點就會等,等到大小足夠大或者超時時間。這些設(shè)置是在configtx.yaml中配置的。
開發(fā)人員如果要自定義出塊的時間和每個區(qū)塊內(nèi)交易的數(shù)量,可以參考文檔:
https://link.zhihu.com/?target=https%3A//github.com/hyperledger/fabric/blob/release/sampleconfig/configtx.yaml
主要的相關(guān)的配置項如下:
# Batch
Timeout: The amount of time to wait before creating a batch.
BatchTimeout: 2s
# Batch Size:
Controls the number of messages batched into a block.
BatchSize:
# Max Message
Count: The maximum number of messages to permit in a
# batch.
MaxMessageCount:
10
# Absolute Max Bytes: The absolute
maximum number of bytes allowed for
# the serialized messages in a batch.
If the "kafka" OrdererType is
# selected, set 'message.max.bytes' and
'replica.fetch.max.bytes' on the
# Kafka brokers to a value that is
larger than this one.
AbsoluteMaxBytes: 10 MB
# Preferred Max Bytes: The preferred
maximum number of bytes allowed for
# the serialized messages in a batch. A
message larger than the
# preferred max bytes will result in a
batch larger than preferred max
# bytes.
PreferredMaxBytes: 512 KB
# Max
Channels is the maximum number of channels to allow on the ordering
# network.
When set to 0, this implies no maximum number of channels.
MaxChannels:
0
這里主要的配置項是BatchTimeout和MaxMessageCount。
BatchTimeout是配置多久產(chǎn)生一個區(qū)塊,默認(rèn)是2秒,通常在項目實踐中,我們發(fā)現(xiàn)交易量并不大,如果配置的時間過小就會產(chǎn)生很多空的區(qū)塊,配置時間太長,則發(fā)現(xiàn)等待產(chǎn)生區(qū)塊的時間太長。具體時間由交易頻率和業(yè)務(wù)量決定。我們實際項目中,通常配置在30秒。
MaxMessageCount是配置在一個區(qū)塊中允許的交易數(shù)的最大值。默認(rèn)值是10。交易數(shù)設(shè)置過小,導(dǎo)致區(qū)塊過多,增加orderer的負(fù)擔(dān),因為要orderer要不斷的打包區(qū)塊,然后deliver給通道內(nèi)的所有peer,這樣還容易增加網(wǎng)絡(luò)負(fù)載,引起網(wǎng)絡(luò)擁堵。我們實際項目中通常配置500,不過具體還應(yīng)該看業(yè)務(wù)情況,因為如果每個交易包含的數(shù)據(jù)的size如果太大,那么500個交易可能導(dǎo)致一個區(qū)塊太大,因此需要根據(jù)實際業(yè)務(wù)需求權(quán)衡。
讀者可能有一個疑問,這里有2個參數(shù)可以配置區(qū)塊的出塊策略,那么究竟那個因素優(yōu)先發(fā)生作用呢?實際上根據(jù)Fabric設(shè)計的出塊策略,BatchTimeout和MaxMessageCount的任何一個參數(shù)條件滿足,都會觸發(fā)產(chǎn)生新的區(qū)塊。舉個例子,假設(shè)我們配置了出塊時間BatchTimeout為30秒,塊內(nèi)交易最大數(shù)量MaxMessageCount為500。第一種情況,當(dāng)出塊時間為20秒(時間上還沒達(dá)到出塊要求),但是交易數(shù)已經(jīng)累積到500個了,這個時候也會觸發(fā)新的區(qū)塊產(chǎn)生。第二種情況,交易數(shù)才1個,但是出塊時間已經(jīng)30秒了,這個時間也會觸發(fā)新的區(qū)塊產(chǎn)生,盡管這個新的區(qū)塊里只有一個交易。
Fabric的這種出塊策略設(shè)計相比還是比較靈活的,可配置的。相比而言,在比特幣中,大家都知道出塊機制是固定的,就是每隔10分鐘(600秒)產(chǎn)生一個區(qū)塊,就一個陌生,不可更改。而以太坊類似,也是基于事件的出塊策略,只是時間更短,每15秒產(chǎn)生一個區(qū)塊。因此,F(xiàn)abric的出塊策略在設(shè)計上還是比較進(jìn)步的。

第六階段
共識服務(wù)節(jié)點將打包的區(qū)塊廣播道同一個通道的所有peer,通過Fabric提供的deliver RPC服務(wù),共識服務(wù)節(jié)點和peer節(jié)點之間的通信細(xì)節(jié),我們在稍后詳細(xì)介紹。必須說明的是,E4和E5不在同樣的通道上(或者說不屬于同樣的子賬本),因此E4,E5不會收到任何更新消息。另外,共識網(wǎng)絡(luò)節(jié)點只是涉及到排序交易和打包區(qū)塊,不會執(zhí)行智能合約。

第七階段
Peers收到共識網(wǎng)絡(luò)發(fā)來的區(qū)塊后,會先進(jìn)行以下校驗:
n 再次驗證區(qū)塊中的交易以確保背書策略滿足。
n 檢查區(qū)塊的數(shù)據(jù)是否正確。
n 對每個交易進(jìn)行驗證,確保自從讀集合數(shù)據(jù)在交易執(zhí)行生成后,讀集合變量對應(yīng)的賬本的狀態(tài)沒有變化,也就是驗證交易中的讀寫數(shù)據(jù)集是否與State Database的數(shù)據(jù)版本一致。
驗證通過后,區(qū)塊中的交易打上合法和非法交易的標(biāo)簽,然后添加區(qū)塊到通道對應(yīng)的鏈上,同時把所有驗證通過的交易的讀寫集中的寫的部分寫入狀態(tài)數(shù)據(jù)庫State Database。對于每個合法交易,寫集合被提交到當(dāng)前的狀態(tài)數(shù)據(jù)庫。同時,一個區(qū)塊事件產(chǎn)生并發(fā)出,通知客戶應(yīng)用,交易已經(jīng)不可更改的添加到了鏈上,也是告訴應(yīng)用客戶端,交易是合法還是非法。
另外對于區(qū)塊鏈,本身是文件系統(tǒng),不是數(shù)據(jù)庫,所有也會有把區(qū)塊中的數(shù)據(jù)在LevelDB中建立索引。
