Fabric架構(gòu)

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

Fabric模塊

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

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

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

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

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

第五階段
客戶端應(yīng)用將交易和響應(yīng)信息封裝到一個(gè)事務(wù)消息(transaction message)中,然后廣
播到共識(shí)網(wǎng)絡(luò)(這里的共識(shí)網(wǎng)絡(luò)又稱為排序服務(wù)Ordering Service,后續(xù)統(tǒng)一稱為共識(shí)網(wǎng)絡(luò))。交易中包含讀寫集,背書節(jié)點(diǎn)簽名和通道 ID。
共識(shí)網(wǎng)絡(luò)節(jié)點(diǎn)不會(huì)關(guān)注交易細(xì)節(jié)和交易消息的具體內(nèi)容,只是簡(jiǎn)單地從網(wǎng)絡(luò)中接收來自所有通道的交易,然后按通道按時(shí)間順序排序,處理的結(jié)果是一個(gè)Batch的交易,也就是一個(gè)區(qū)塊,這個(gè)區(qū)塊的產(chǎn)生有兩種情況,一種情況是區(qū)塊中的交易很多,區(qū)塊的大小達(dá)到了配置文件中配置的大小,而另一種情況是區(qū)塊中的交易很少,沒有達(dá)到配置的大小,那么共識(shí)網(wǎng)絡(luò)節(jié)點(diǎn)就會(huì)等,等到大小足夠大或者超時(shí)時(shí)間。這些設(shè)置是在configtx.yaml中配置的。
開發(fā)人員如果要自定義出塊的時(shí)間和每個(gè)區(qū)塊內(nèi)交易的數(shù)量,可以參考文檔:
https://link.zhihu.com/?target=https%3A//github.com/hyperledger/fabric/blob/release/sampleconfig/configtx.yaml
主要的相關(guān)的配置項(xiàng)如下:
# 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
這里主要的配置項(xiàng)是BatchTimeout和MaxMessageCount。
BatchTimeout是配置多久產(chǎn)生一個(gè)區(qū)塊,默認(rèn)是2秒,通常在項(xiàng)目實(shí)踐中,我們發(fā)現(xiàn)交易量并不大,如果配置的時(shí)間過小就會(huì)產(chǎn)生很多空的區(qū)塊,配置時(shí)間太長(zhǎng),則發(fā)現(xiàn)等待產(chǎn)生區(qū)塊的時(shí)間太長(zhǎng)。具體時(shí)間由交易頻率和業(yè)務(wù)量決定。我們實(shí)際項(xiàng)目中,通常配置在30秒。
MaxMessageCount是配置在一個(gè)區(qū)塊中允許的交易數(shù)的最大值。默認(rèn)值是10。交易數(shù)設(shè)置過小,導(dǎo)致區(qū)塊過多,增加orderer的負(fù)擔(dān),因?yàn)橐猳rderer要不斷的打包區(qū)塊,然后deliver給通道內(nèi)的所有peer,這樣還容易增加網(wǎng)絡(luò)負(fù)載,引起網(wǎng)絡(luò)擁堵。我們實(shí)際項(xiàng)目中通常配置500,不過具體還應(yīng)該看業(yè)務(wù)情況,因?yàn)槿绻總€(gè)交易包含的數(shù)據(jù)的size如果太大,那么500個(gè)交易可能導(dǎo)致一個(gè)區(qū)塊太大,因此需要根據(jù)實(shí)際業(yè)務(wù)需求權(quán)衡。
讀者可能有一個(gè)疑問,這里有2個(gè)參數(shù)可以配置區(qū)塊的出塊策略,那么究竟那個(gè)因素優(yōu)先發(fā)生作用呢?實(shí)際上根據(jù)Fabric設(shè)計(jì)的出塊策略,BatchTimeout和MaxMessageCount的任何一個(gè)參數(shù)條件滿足,都會(huì)觸發(fā)產(chǎn)生新的區(qū)塊。舉個(gè)例子,假設(shè)我們配置了出塊時(shí)間BatchTimeout為30秒,塊內(nèi)交易最大數(shù)量MaxMessageCount為500。第一種情況,當(dāng)出塊時(shí)間為20秒(時(shí)間上還沒達(dá)到出塊要求),但是交易數(shù)已經(jīng)累積到500個(gè)了,這個(gè)時(shí)候也會(huì)觸發(fā)新的區(qū)塊產(chǎn)生。第二種情況,交易數(shù)才1個(gè),但是出塊時(shí)間已經(jīng)30秒了,這個(gè)時(shí)間也會(huì)觸發(fā)新的區(qū)塊產(chǎn)生,盡管這個(gè)新的區(qū)塊里只有一個(gè)交易。
Fabric的這種出塊策略設(shè)計(jì)相比還是比較靈活的,可配置的。相比而言,在比特幣中,大家都知道出塊機(jī)制是固定的,就是每隔10分鐘(600秒)產(chǎn)生一個(gè)區(qū)塊,就一個(gè)陌生,不可更改。而以太坊類似,也是基于事件的出塊策略,只是時(shí)間更短,每15秒產(chǎn)生一個(gè)區(qū)塊。因此,F(xiàn)abric的出塊策略在設(shè)計(jì)上還是比較進(jìn)步的。

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

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