当前位置:主页 > 查看内容

联盟链 fabric 数据库 数据存储

发布时间:2021-08-03 00:00| 位朋友查看

简介:Hyperledger Fabric区块链结构由区块头和区块体组成并通过父区块哈希编码构成唯一链接Hyperledger Fabric加入一层状态缓存设计用以提高读写性能。 Hyperledger Fabric本质上是一个分布式账本在底层结构中都是通过键值对的方式来存储数据。而区块链1.0为了实……

Hyperledger Fabric区块链结构由区块头和区块体组成,并通过父区块哈希编码构成唯一链接,Hyperledger Fabric加入一层状态缓存设计,用以提高读写性能。

Hyperledger Fabric本质上是一个分布式账本,在底层结构中都是通过键值对的方式来存储数据。而区块链1.0为了实现数据的时间可回溯性和数据防篡改机制,在链中并不保存数据的状态,而只保存对数据的变更。这就使得对某条数据的状态查询需要进行全链遍历,其查询性能很难满足一些企业级业务的性能需求,因此Hyperledger Fabric引入了“世界状态(World State)”这一概念。

Fabric 里的数据以分布式账本的形式存储。账本由一系列有顺序和防篡改的记录组成,记录包含着数据的全部状态改变。账本中的数据项以键值对的形式存放,账本中所有的键值对构成了账本的状态,也称为“世界状态”( World State )。当区块中保存某一条记录时,会同步更新对应Key的世界状态。当需要查询某个键值时,只需要查询对应的世界状态即可,而无需进行全链遍历。

世界状态是脱链保存在LevelDB/CouchDB结构中的,是一种链外附加缓存机制,世界状态的丢失并不会对区块链中的数据产生影响。

每个通道中有唯一的账本,由通道中所有成员共同维护着这个账本,每个确认节点上都保存了它所属通道的账本的一个副本,因而是分布式账本。对账本的访问需要通过链码实现对账本键值对的增加、删除、更新和查询等的操作。

账本由区块链(File System)和状态数据库(Level DB)两部分组成。如下图所示
在这里插入图片描述

状态数据库,记录了账本中所有键值对的当前值,相当于对当前账本的交易日志做了索引。链码执行交易的时候需要读取账本的当前状态,从状态数据库可以迅速获取键值的最新状态。

如果没有状态数据库,要获得某个键值时,需要遍历整个区块链中和该键值相关的交易,效率非常低,因此,读取状态数据库可以认为是快速定位和访问某个键值的方法。另外,当状态数据库出现故障的时候,可以通过遍历账本重新生成。

当一个区块附加到区块链尾部的时候,如果区块中的有效交易修改了键值对,则会在状态数据库中作相应的更新,这样区块链和状态数据库始终保持一致。

状态数据库原理上可以是各种键值数据库,Fabric 缺省使用的是 LevelDB ,也支持 CouchDB 的选项。CouchDB 除了支持键值数据之外,也支持 JSON 格式的文档模型,能够做复杂的查询。

数据存在节点:

/var/hyperledger/production/ledgersData

在这里插入图片描述
peer节点上账本数据库与区块数据文件路径的默认配置列表

数据库与文件文件路径
id store数据库/var/hyperledger/production/ledgersData/ledgerProvider
区块数据文件/var/hyperledger/production/ledgersData/chains/chains
隐私数据库/var/hyperledger/production/ledgersData/pvtdataStore
区块索引数据库/var/hyperledger/production/ledgersData/chains/index
状态数据库LevelDB默认为/var/hyperledger/production/ledgersData/stateLeveldb CouchDB需要指定服务器地址、用户名、密码等配置参数
历史数据库/var/hyperledger/production/ledgersData/historyLeveldb
transient隐私数据库/var/hyperledger/production/transientStore

(1)chains:chains/chains下包含的mychannel是对应的channel的名称,因为Fabric是有多channel的机制,而channel之间的账本是隔离的,每个channel都有自己的账本空间。chains/index下面包含的是levelDB数据库文件,在Fabric中默认所有的数据库都是LevelDB,这个原因作者下面会讲到,DB中存储的就是我们上面说的区块索引部分。chains/chains和chains/index就是上面所说的File System和indexDB;

(2)stateLeveldb: 同样是levelDB数据库,存储的是智能合约putstate写入的数据;

(3)ledgerProvider:数据库内存储的是当前节点所包含channel的信息(已经创建的channel id 和正在创建中的channel id),主要是为了Fabric的多channel机制服务的;

(4)historyLeveldb:数据库内存储的是智能合约中写入的key的历史记录的索引地址。

order节点上账本数据库与区块数据文件路径的默认配置列表

数据库与文件文件路径
区块数据文件/var/hyperledger/production/orderer/chains
区块索引数据库/var/hyperledger/production/orderer/index

peer节点账本存储图如下

在这里插入图片描述
1 左边区块链是狭义的区块存储,底层是一个文件系统,区块并不是存储在数据库,而是直接存储为文件
2 右半部分的区块索引用于查询区块,将区块属性与区块位置相关联,例如通过区块hash、区块高度、交易id查询区块数据,区块索引的实现使用了内置数据库Leveldb
3 历史数据索引 启用与否取决于智能合约是否有查询历史的需求,记录某个键值在某条交易中被改变,只记录改变动作,不记录具体改变
4 状态数据库存储当前区块链上最新的数据,以键值对key-value的形式存储所有键的最新值

账本存储源码:
状态数据库: 可选leveldb、couchdb

vim /opt/gopath/src/github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

在这里插入图片描述
历史数据库

vim /opt/gopath/src/github.com/hyperledger/fabric/core/ledger/kvledger/history/db.go

在这里插入图片描述
区块文件读取:

vim /opt/gopath/src/github.com/hyperledger/fabric/common/ledger/blkstorage/blockstore.go

在这里插入图片描述
区块链数据操作 —查询
区块链数据操作 —添加

调用链码发起查询操作的时候,查的就是世界状态当中的值,因为查询操作不会对账本的当前状态造成任何改变。

而当调用链码发起写操作(更改,删除,增加)时,应用程序提交一个交易提案到背书节点,背书节点背书之后返回,应用程序再将交易发送给排序节点排序。之后排序节点将交易打包成区块,将区块分发给各个组织的 peer 节点。此时,如果该交易是一笔无效交易(比如验证签名失败,背书失败等等原因),那么该笔交易只会被存储到本地的交易记录中,但是不会更改账本的世界状态——即无效交易不会导致账本世界状态的改变。

另外,世界状态中的每个状态都有一个版本号,版本号供 Fabric 内部使用,并且每次状态更改时版本号都会发生递增。举个例子,其当前状态版本号都是0,当发生了一次对账本对象的写操作的时候,账本的状态就发生了变化,这样的新的世界状态就产生了,其中的状态的版本号就是1。

每当更新状态时,都会检查该状态的版本,以确保当前状态与背书时的版本相匹配。这就确保了世界状态是按照预期进行更新的,没有发生并发更新,是并发安全的。

首次创建账本时,世界状态是空的。因为区块链上记录了所有代表有效世界状态更新的交易,所以任何时候都可以从区块链中重新生成世界状态。这样一来就变得非常方便,例如,创建节点时会自动生成世界状态。此外,如果某个节点发生异常,重启该节点时能够在接受交易之前重新生成世界状态。

;原文链接:https://blog.csdn.net/weixin_41303815/article/details/115803249
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:C/C++编程笔记:C结构和C++结构之间的区别 下一篇:没有了

推荐图文


随机推荐