区块链可追溯、不可篡改的特性要求系统内每个节点保存一份数据,且数据量日益增长,这对于部分大数据量系统中的海量数据存储及导致的数据处理效率降低带来了挑战,这其中就需要考虑数据在实际存储中的膨胀问题。

 区块存储流程 

要理解数据膨胀问题,首先了解以下长安链的区块存储方式及流程。⻓安链在v2.2以后开始⽀持区块⽂件存储,适合区块数据库⼤于400GB以后的场景,采⽤与之前⽅案不同的区块存储⽅式以解决⽇益增⻓的区块数据导致节点速度变慢的问题:将区块数据直接顺序放到磁盘中,同时建⽴区块存放位置的索引,将索引信息放置到区块数据库中,在读取区块数据(区块/交易/读写集)时直接从⽂件中截取,然后反序列化返回,极大减轻了kv数据的存储压力。

当前区块写⼊架构图如下:

图1

 数据膨胀的产生 

这里我们理解的“数据膨胀”不同于链上的“数据增长”。在区块链的运行过程中,我们通常是以交易为操作单位,但是在存储过程中我们不能只是记录交易信息。就像旅客出门有行李,考虑汽车上载人的数量和耗油的时候还需要额外考虑乘客行李的尺寸和重量。为了更好的组织链上的交易,我们需要使用区块将交易组织起来,同时交易中也需要包含除了纯粹交易信息以外的内容。所以区块中就多了区块头,交易中就多了一些交易参数,如:chainId, TxType等。此时存储一个交易就附带的很多内容(就像旅客的行李),这就产生了数据膨胀。本篇文章对长安链在实际存储过程中数据膨胀的原因和实际膨胀大小做一次简单的探讨。

 ⽂件存储结构 

在区块链中总是以区块为前进的单位。我们说区块链运行了多远,一般都会说区块链的高度是xxx了,比如某链高度到达15389182了,实际意思是说这条链当前已经处理和存储了15389182个区块链了。长安链也是如此,每一个区块运行之后都会通过长安的存储模块最后存储到磁盘上。长安链在区块实际存储过程中发现:以往的区块数据直接存储在KV数据库的方式会导致数据库(如:leveldb)压力过大,而且在一定存储量之后出现数据库无论是写入还是查询效率都急剧下降的问题。为了解决这个问题,长安链自主开发了基于文件存储的区块存储方式:将区块数据放入到自研的文件存储,然后将相关的索引放入KV数据库(如:leveldb)中。改良之后测试发现,数据库的压力急剧降低,在已经测试的16TB的存储量下(单节点单leveldb),存储模块性能也毫不下降。那么长安链的存储模块到底是如何存储的呢?

1.区块在到达存储模块后会进行序列化操作,为下一步区块数据落盘做准备,此时我们将区块对象中的子对象单独序列化,同时记录序列化产生字节流的长度,然后再拼接起来,就是一个序列化之后的完整区块的字节流。

2.在序列化和拼接的时候记录子对象在区块字节流的偏移量和长度,即: 某子对象在整个区块字节流的起始位置和长度,在反序列化字节流成对象的时候直接截取区块指定位置特定长度的片段,再反序列化,即可得到原始对象。

3.在读取区块/交易/读写集/事件日志时,从KV数据库中获取区块所在的fdb文件名和在该文件中的起始和长度,然后再反序列化即可。

4.长安链在文件存储中定义了区块存储的文件.fdb文件,用于存放每次产生的区块文件。

5.文件存储结构图如下:

图2

KV存储schema及size 

KV存储是前面区块写入架构图(图1)的下面半截的部分的数据的存储,从图中可以看到存储主要分为分为blockdb、statedb、historydb、resultdb四个数据库。在关系型数据库中,数据一般以表为单位进行组织管理,这种表的关系和属性就是schema,而长安链采用的是leveldb类型的非关系型数据库中,在数据的组织中也有一套自己的schema。下面列出每个数据库的schema结构,同时在后面的注释中标记出每对KV在本次测试统计中的实际存储大小。

blockdb

batch.Put([]byte(lastBlockNumKeyStr), lastBlockNumBytes) lastBlockNumKey block.Header.BlockHeight  //len: key 15, value 1

batch.Put(blockIndexKey, blockIndexInfo) //len: key 3, value 29

batch.Put(metaIndexKey, metaIndexInfo)   //len: key 3, value 29

batch.Put(hashKey, encodeBlockNum(block.Header.BlockHeight))  //len: key 33, value 1

for --

batch.Put(blockTxIdKey, txBlockInf)  //len: key 65, value 39

--

batch.Put([]byte(lastConfigBlockNumKey), heightKey) //配置区块才会有 len: key 21, value 1

statedb

batch.Put([]byte(stateDBSavepointKey), lastBlockNumBytes) //len: key 19, value 8

for --

batch.Put(txWriteKey, txWrite.Value) //len: key 56, value 4 // contract_name_count_rust#count#B_0_0_1660100497149619000

--

historydb

batch.Put([]byte(historyDBSavepointKey), lastBlockNumBytes) //len: key 19, value 8

for --

batch.Put(constructKey(write.ContractName, write.Key, blockHeight, txId, txIndex), []byte{0}) //len: key:127 value: 1 kcontract_name_count_rust#count#B_0_0_1660100497149619000#21#0$1709dc9b4813eb48ca4c926abcc8de5f9fd7c4c863d547da9459dfab24c2b298

--

//本次测试未开启该模块存储

// for --

// batch.Put(constructAcctTxHistKey(accountId, blockHeight, txId), []byte{0}) //len: key: 14+64=78 value: 1

// batch.Put(constructContractTxHistKey(contractName, blockHeight, txId), []byte{0}) //len: key: 4+64=68 value: 1

// --

resultdb

batch.Put([]byte(resultDBSavepointKey), lastBlockNumBytes) //len: key 18, value 8

for --

batch.Put(rwSetIndexKey, rwIndexInfo) //len: key: 2+64=66 value: 29

--

 区块对象空间占⽤详细分析 

本次统计使⽤的是counter-rust.wasm合约,对应的交易⼤⼩为4KB 膨胀率(公众号对话框回复【数据膨胀】获取原图)。

以下图片可点击放大

图4

 膨胀率公式总结 

本次测试中所采用的存证类型合约在交易全部并行运行时的数据膨胀公式:

1.Tbft:使用tbft共识

2.Raft:使用raft共识

3.Read:读集:指使用ctx.getStatexxxx

4.Write:写集:指使用ctx.putStatexxxx

5.Event:事件:指使用ctx.event(xxxxxx

blockFileDbSize = (Tbft(8,346) or Raft(2,603)) +

len(ChainId+orgId) + txCount * 2 +

(

1,196 + len(ChainId + orgId + ContractName + Method + key + val) +

Event(len(topicName + contractName + eventData) + 64) +

len(result) +

Read(len(key + field + 1 + value + contractName)) +

Write(len(key + field + 1 + value + contractName))

) * txCount

blockIndexDbSize = blockFileDbSize * 0.07

stateDbSize = Write(len(key + field + 1 + value + contractName) * txCount

 结  语 

本次总结的公式长,变量多,需要根据实际的合约以及调用参数做实际的膨胀率统计。同时长安链也在探索更多的方案来降低存储数据膨胀率,降低存储成本,欢迎业内朋友提出更加优秀的方案,提升长安链存储效率。

长安链大规模数据存储及数据膨胀分析相关推荐

  1. 深圳家庭数据存储 家庭数据备份 数蚁科技

    深圳家庭数据存储 家庭数据备份 数蚁科技 使用数蚁家庭数据存储撰写家庭计划,发起讨论.让一切计划有序进行.出游计划,使用数蚁家庭数据存储规划家庭出游地点.途经 风景点.食宿安排以及注意事项,和家人一起 ...

  2. influxDB框架 数据存储 TSM 数据操作等详解

    文章目录 influxdb influxdata主目录结构 源码主目录结构 cmd目录 其他目录 数据操作 CLI--influx命令行操作 执行influx 创建数据库 查看数据库 使用数据库 数据 ...

  3. 软件测试数据存储位置,关于数据存储类型的一点分析

    简介 SQL Server每个表中各列的数据类型的有各种形式,产生的效果也各有不同,我们主要根据效率兼顾性能的情况下讨论下如何规定类型. 在SQL Server中,数据的存储以页为单位.八个页为一个区 ...

  4. android之数据存储,Android数据存储之File

    Android使用与其他平台类似的基于磁盘文件系统(disk-based file systems),上篇文章通过SharedPerference来进行数据存储,这次可以使用File.File 对象非 ...

  5. gps数据存储mysql_gps数据存储mysql

    gps数据存储mysql 云服务器(Elastic Compute Service,简称ECS)是阿里云提供的性能卓越.稳定可靠.弹性扩展的IaaS(Infrastructure as a Servi ...

  6. 08_clickhouse主键/索引的工作机制(MergeTree的稀疏索引、索引的生成过程、索引的查询),数据标记的工作机制(数据存储、数据标记、数据查询、数据查询示例)(学习笔记)

    5.主键/索引的工作机制 5.1.MergeTree的稀疏索引 5.2.索引的生成过程 5.3.索引的查询 6.数据标记的工作机制 6.1.数据存储 6.2.数据标记 6.3.数据查询 6.4.数据查 ...

  7. 05_ClickHouse、MergeTree系列引擎概述与存储结构、建表模板、建表语句、MergeTree设置、建表示例、数据存储、数据片段(data part)

    2.MergeTree系列引擎概述与存储结构 2.1.建表模板 2.2.建表语句 2.3.MergeTree设置 2.4.建表示例 2.5.数据存储 2.6.数据片段(data part) 2.Mer ...

  8. 数据存储:数据备份:测试备份和还原

    此页面显示如何手动触发自动备份,键/值备份和还原操作,以确保您的应用程序正确保存和恢复数据. 一.备份如何运行 该部分介绍了Android备份框架中的各种功能,以及它们如何与支持自动备份和键/值备份的 ...

  9. 数据存储:数据备份:自动备份

    自从Android 6.0(API 23)以来,Android已经提供了自动备份应用程序功能,作为开发人员快速添加备份功能到他们的应用程序的一种方式. 自动备份通过将应用数据上传到用户的Google云 ...

最新文章

  1. unix mysql命令大全_mySql的一些常用命令
  2. 国内大陆芯片70个细分领域重要代表企业!
  3. [编程题]字符串最后一个单词的长度
  4. 怎么把照片做成立方体在html播放,立方体照片.html
  5. SQL反模式笔记17——用一条sql解决复杂问题
  6. 用VS2012或VS2013在win7下编写的程序在XP下运行就出现“不是有效的win32应用程序
  7. python怎么处理文字_python 处理给规范的文字
  8. java用一个方法对变量初始化_java中怎么给变量初始化?
  9. 大丈夫 · 心の中の大丈夫さん
  10. 图解Python编程:从入门到精通系列教程(附全套速查表)
  11. 外壳和接地层对天线的影响
  12. jar 坐标系转换工具_谷歌百度经纬度转换
  13. 打不开.chm文件jdk的API
  14. MySQL密码正确却无法登录
  15. Catch the moments of your life. Catch them while you're young and quick.
  16. 计算机应用情话,情话大全浪漫情话 最美的情话莫过于我也爱你
  17. 你的每行代码值多少钱?
  18. Java应届生大学四年怎么做,可以毕业就进入华为工作,致Java高级工程师的一封信
  19. python新闻聚合_基于Python的新闻聚合系统网络爬虫研究
  20. Spring Security Oauth2 JWT 实现用户认证授权功能

热门文章

  1. hihoCoder挑战赛12 顺子(hihocoder 1177)
  2. C++常见的三种中文内码转换代码
  3. 多种方法进行去基线处理
  4. 遗传算法GA算法思路及其C++实现
  5. matlab体素化,一种三维激光点云数据快速体素化处理方法与流程
  6. MATLAB S-function(教程分享) 报错 flag = 3(output), at time 0.0. 输入参数的数目不足。
  7. eclipse 3.7(indigo)在线安装中文语言包
  8. JAVA泛型尖括号中的 T 和 ? 有什么区别?
  9. oracle vba 数组_vba 数据库目录
  10. android studio开发rtk,Android安卓平板电脑