让木桶没有短板,FISCO BCOS全面推进区块链并行化改造

2023-10-31

FISCO BCOS是完全开源的联盟区块链底层技术平台,由金融区块链合作联盟(深圳)(简称金链盟)成立开源工作组通力打造。开源工作组成员包括博彦科技、华为、深证通、神州数码、四方精创、腾讯、微众银行、亦笔科技和越秀金科等金链盟成员机构。

代码仓库:https://github.com/FISCO-BCOS

 

背 景

PTE(Parallel Transaction Executor,一种基于DAG模型的并行交易执行器)的引入,使FISCO BCOS具备了并行执行交易的能力,显著提升了节点交易处理的效率。对这个阶段性结果,我们并不满足,继续深入挖掘发现,FISCO BCOS的整体TPS仍有较大提升空间。

用木桶打个比方:如果参与节点的交易处理所有模块构成木桶,交易执行只是组成整个木桶的一块木板,根据短板理论,一只木桶能盛多少水取决于桶壁上最矮的那块,同理,FISCO BCOS的性能也由速度最慢的组件决定

尽管PTE取得了理论上极高的性能容量,但是FISCO BCOS的整体性能仍然会被其他模块较慢的交易处理速度所掣肘。为了能够最大化利用计算资源以进一步提高交易处理能力,在FISCO BCOS中全面推进并行化改造势在必行。

 

数据分析

根据并行程序设计的『分析→分解→设计→验证』四步走原则,首先需定位出系统中仍存在的性能瓶颈的精确位置,才能更深入地对任务进行分解,并设计相应的并行化策略。使用自顶向下分析法,我们将交易处理流程分为四个模块进行性能分析,这四个模块分别是:

区块解码(decode):区块在节点间共识或同步时需要从一个节点发送至另一个节点,这个过程中,区块以RLP编码的形式在网络间传输。节点收到区块编码后,需要先进行解码,将区块还原为内存中的二进制对象,然后才能做进一步处理。

交易验签(verify):交易在发送之前由发送者进行签名,签名得到的数据可以分为(v, r, s)三部分,验签的主要工作便是在收到交易或交易执行前,从(v, r, s)数据中还原出交易发送者的公钥,以验证交易发送者的身份。

交易执行(execute):执行区块中的所有交易,更新区块链状态。

数据落盘(commit):区块执行完成后,需要将区块及相关数据写入磁盘中,进行持久化保存。

以包含2500笔预编译转账合约交易的区块为测试对象,在我们的测试环境中,各阶段的平均耗时分布如下图所示:

e3b8392a9435a3ab83b816cbe97e29c3475.jpg

从图中可以看出,2500笔交易的执行时间已经被缩短到了50毫秒以内,可以证明PTE对FISCO BCOS交易执行阶段的优化是行之有效的。但图中也暴露出了非常明显的问题:其他阶段的用时远远高于交易执行的用时,导致交易执行带来的性能优势被严重抵消,PTE无法发挥出其应有的价值。

早在1967年,计算机体系结构领域的元老Amdahl提出的以他名字命名的定律,便已经向我们阐明了衡量处理器并行计算后效率提升能力的经验法则:

85b68379bb12699c8da3daefd5cf1b5f1f4.jpg

其中,SpeedUp为加速比,Ws是程序的串行分量,Wp是程序中的并行分量,N为CPU数量。可以看出,在工作总量恒定的情况下,可并行部分代码占比越多,系统的整体性能越高。我们需要把思维从线性模型中抽离出来,继续细分整个处理流程,找出执行时间最长的程序热点,对这些代码段进行并行化从而将所有瓶颈逐个击破,这才是使通过并行化获得最大性能提升的最好办法。

 

根因拆解

 

1.串行的区块解码

区块解码主要性能问题出在RLP编码方法本身。RLP全称是递归的长度前缀编码,是一种用长度作为前缀标明编码对象中元素个数的编码方法。如下图所示,RLP编码的开头即是此编码中的对象个数(Object num)。在个数后,是相应个数的对象(Object)。递归地,每个对象,也是RLP编码,其格式也与下图相同。

需要特别注意的是,在RLP编码中。每个Object的字节大小是不固定的,Object num只表示Object的个数,不表示Object的字节长度。

f3634c814ed8d9b402e537fd7cbe8e47136.jpg

RLP通过一种长度前缀与递归结合的方式,理论上可编码任意个数的对象。下图是一个区块的RLP编码,在对区块进行编码时,先递归至最底层,对多个sealer进行编码,多个sealer被编码并加上长度前缀后,编码成为一串RLP编码(sealerList),此编码又作为一个对象,被编入上层的一串RLP编码(blockHeader)中。此后层层递归,最后编码成为区块的RLP编码。由于RLP编码是递归的,在编码前,无法获知编码后的长度。

9cd2ede196c7909aea8375e92c3c969cfba.jpg

解码时,由于RLP编码中每个对象的长度不确定,且RLP编码只记录了对象的个数,没记录对象的字节长度,若要获取其中的一个编码对象,必须递归解码其前序的所有对象,在解码前序的对象后,才能访问到需要访问的编码对象的字节位置。例如在上图中,若需要访问区块中的第0笔交易,即tx0,必须先将blockHeader解码,而blockHeader的解码,需要再次递归,把parentHash,stateRoot直至sealerList都解码出来。

解码区块最重要的目的是解码出包含在区块中的交易,而交易的编码都是互相独立的,但在RLP特殊的编码方式下,解码一笔交易的必要条件是解码出上一笔交易,交易的解码任务之间环环相扣,形成了一种链式的依赖关系。需要指出的是,这种解码方式并不是RLP的缺陷,RLP的设计目标之一本就是尽量减少空间占用,充分利用好每一个字节,虽然编解码变得低效了些,但编码的紧凑度却是有目共睹,因此这种编码方式本质上还是一种时间换空间的权衡结果。

由于历史原因,FISCO BCOS中使用了RLP编码作为多处信息交换协议,贸然换用其他并行化友好的序列化方案可能会带来较大的开发负担。基于这一考虑,我们决定在原有的RLP编解码方案稍作修改,通过为每个被编码的元素添加额外的位置偏移信息,便可以做到并行解码RLP的同时不会改动大量原有代码。

 

2.交易验签 & 数据落盘开销大

通过对交易验签和数据落盘部分的代码进行拆解,我们发现两者的主要功能都集中在一个耗时巨大的for循环。交易验签负责按序取出交易,然后从交易的签名数据中取出(v, r, s)数据,并从中还原出交易发送者的公钥,其中,还原公钥这一步,由于涉及密码学算法,因此耗时不少;数据落盘负责从缓存中逐个取出交易相关数据,将其编码为JSON字符串后写入磁盘,由于JSON编码过程本身效率比较低,因此也是性能损失的重灾区。

两者代码分别如下所示:

3885be80b84e14db1653111d88430ee5d2b.jpg

两个过程共有的特点是,它们均是将同样的操作应用到数据结构中不同的部分,对于这种类型的问题,可以直接使用数据级并行进行改造。所谓数据级并行,即是将数据作为划分对象,通过将数据划分为大小近似相等的片段,通过在多个线程上对不同的数据片段上进行操作,达到并行处理数据集的目的。

数据级并行唯一的附加要求是任务之间彼此独立,毫无疑问,在FISCO BCOS的实现中,交易验签和数据落盘均满足这一要求。

 

优化实践

 

1.区块解码并行化

改造过程中,我们在系统中使用的普通RLP编码的基础上,加入了offset字段,用以索引每个Object的位置。如下图所示,改造后编码格式的开头,仍然是对象的个数(Object num),但是在个数字段后,是一个记录对象偏移量的数组(Offsets)。

39bb99274c8aa36f01e9dfa595eaebf4225.jpg

数组中的每个元素有着固定的长度。因此要读取某个Offset的值,只需向访问数组一样,根据Offset的序号直接索引便可以进行随机访问。在Offsets后,是与RLP编码相同的对象列表。相应序号的Offset,指向相应序号的对象的RLP编码字节位置。因此,任意解码一个对象,只需要根据对象的序号,找到其偏移量,再根据偏移量,就可定位到相应对象的RLP编码字节位置。

编码流程也进行了重新设计。流程本身仍然基于递归的思路,对于输入的对象数组,首先将对象数组的大小编码在输出编码的开头处,若数组大小超过1,则按序逐个取出待编码对象并缓存其递归编码,并在Offsets数组中记录该对象的偏移位置,待数组遍历完后,将缓存的对象编码第一次性取出并附加至输出编码末尾;若数组大小为1,则递归对其编码并写入输出编码的末尾,结束递归。

编码流程的伪代码如下:

6fcba44a31f51c51ab052807bc3531edb23.jpg

偏移量的引入使解码模块能够对元素编码进行随机访问。Offsets的数组范围可以在多个线程间均摊,从而每个线程可以并行访问对象数组的不同部分,分别进行解码。由于是只读访问,这种并行方式是线程安全的,仅需最后再对输出进行汇总即可。

解码流程的伪代码如下:

379315f73a58752b43ec89849a9fe36248e.jpg

 

2.交易验签 & 数据落盘并行化

对于数据级并行,业内已有多种成熟的多线程编程模型。虽然Pthread这类显式的多线程编程模型能够提供对线程进行更精细的控制,但是需要我们对线程通信、同步拥有娴熟的驾驭技巧。实现的复杂度越高,犯错的几率越大,日后代码维护的难度也相应增加。我们的主要目标仅仅对密集型循环进行并行化,因此在满足需求的前提下,Keep It Simple & Stupid才是我们的编码原则,因此我们使用隐式的编程模型来达成我们的目的。

经过再三权衡,我们在市面上众多隐式多线程编程模型中,选择了来自Intel的线程构建块(Thread Building Blocks,TBB)开源库。在数据级并行方面,TBB算是老手,TBB运行时系统不仅屏蔽了底层工作线程的实现细节,还能够根据任务量自动在处理器间平衡工作负载,从而充分利用底层CPU资源。

使用TBB后,交易验签和数据落盘的代码如下所示:

18846ec8de121cdc38a418dc21633669b3e.jpg

可以看到,除了使用TBB提供的tbb::parallel_for进行并行循环和tbb::blocked_range引用数据分片外,循环体内的代码几乎没有任何变化,接近C++原生语法正是TBB的特点。TBB提供了抽象层级较高的并行接口,如parallel_for、parallel_for_each这类泛型并行算法,从而使得改造能够较为容易地进行。同时,TBB不依赖任何语言或编译器,只要有能支持ISO C++标准的编译器,便有TBB的用武之地。

当然,使用TBB并不是完全没有额外负担,比如线程间安全还是需要开发人员的仔细分析来保证,但TBB考虑周到,提供了一套方便的工具来辅助我们解决线程间互斥的问题,如原子变量、线程局部存储和并行容器等,这些并行工具同样被广泛地应用在FISCO BCOS中,为FISCO BCOS的稳定运行保驾护航。

 

#写在最后#

经过一套并行优化的组合拳,FISCO BCOS的性能表现更上层楼。压力测试的结果表明,FISCO BCOS的交易处理能力,相较于并行化改造之前,成功提升了1.74倍,基本达到了这个环节的预期效果。

但是我们也深深明白,性能优化之路漫漫,木桶最短的一板总是交替出现,并行之道在于,通过反复的分析、拆解、量化和优化,使得各模块互相配合齐头并进,整个系统达到优雅的平衡,而最优解总是在“跳一跳”才能够得着的地方。

 


 

我们鼓励机构成员、开发者等社区伙伴参与开源共建事业,有你在一起,会更了不起。多样参与方式:

1 进入微信社群,随时随地与圈内最活跃、最顶尖的团队畅聊技术话题(进群请添加小助手微信,微信ID:fiscobcosfan);

2 订阅我们的公众号:“FISCO BCOS开源社区”,我们为你准备了开发资料库、最新FISCO BCOS动态、活动、大赛等信息;

3 来Meetup与开发团队面对面交流,FISCO BCOS正在全国举办巡回Meetup,深圳、北京、上海、成都……欢迎您公众号在菜单栏【找活动】中找到附近的Meetup,前往结识技术大咖,畅聊硬核技术;

4 参与代码贡献,您可以在Github提交Issue进行问题交流,欢迎向FISCO BCOS提交Pull Request,包括但不限于文档修改、修复发现的bug、提交新的功能特性。

代码贡献指引:

https://github.com/FISCO-BCOS/FISCO-BCOS/blob/master/docs/CONTRIBUTING_CN.md

 

本文首发于公众号【FISCO BCOS开源社区】,如转载请注明出处,原创不易,谢谢珍惜

转载于:https://my.oschina.net/u/4119053/blog/3050408

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

让木桶没有短板,FISCO BCOS全面推进区块链并行化改造 的相关文章

  • 如何解码这个 JSON 字符串?

    这是我从 feed finder url 中得到的字符串 JSON 编码 updated 1265787927 id http www google com reader api 0 feed finder q u003dhttp itca
  • 如何在 JsonNode 中创建插入新节点?

    我创建了一个新的 JsonNode JsonNode jNode new ObjectCodec createObjectNode 有了这个节点 我如何在其中添加键值对 以便我可以使用新值构造这个新节点 我读到的内容http www cow
  • 如何对数组的数组进行 JSON_MODIFY?

    我的结构看起来像这样 Declare layout NVARCHAR MAX N Sections SectionName Section1 SectionOrder 1 Renders RenderName Render1 RenderO
  • 数组反序列化的Gson数组

    我有以下 JSON 结构 id 1 subcategories id 2 subcategories id 3 subcategories id 4 subcategories id 5 subcategories 类别的模型类 为简单起见
  • 使用 JSONKit 解析 JSON 文件

    我正在构建一个音叉应用程序 货叉应允许最多 12 个预设节距 此外 我希望允许用户选择一个主题 每个主题都会加载一组预设 不必使用所有预设 我的配置文件看起来像这样 theme A3 comment An octave below conc
  • 使用 Ajax Jquery post 请求进行 Json 劫持

    昨天 我读了一些关于如何预防的好文章使用 Asp Net MVC 进行 Json 劫持 http haacked com archive 2009 06 24 json hijacking aspx 规则是 永远不要通过 get 请求发送
  • 按升序对 NSDictionary 进行排序

    我正在尝试排序NSDictionary按升序排列 我正在使用这段代码 NSDictionary valDict self mGetDataDict key rowKey for NSString valueKey in valDict al
  • 将 json 反序列化为对象:包装类解决方法

    这是我的 json accessType Grant spaces spaceId 5c209ba0 e24d 450d 8f23 44a99e6ae415 privilegeId db7cd037 6503 4dbf 8566 2cca4
  • 参考上一个问题:为什么 VBA 没有加载所有发票详细信息

    除了上一个问题之外 我们在销售发票上仍然存在相同的加载失败问题 下面的 VBA Json 仍然仅加载一行或第一个产品详细信息行 而不是与表中该销售发票合作的所有产品行详细信息 我们希望下面的 VBA 能够根据参数加载发票详细信息 例如 如果
  • 后退按钮 (Chrome) 在 Play Framework 中获取 Json 而不是 HTML

    各位 我有一个 Web 应用程序 我在其中对同一资源的 JSON 和 HTML 表示重复使用了相同的路由 现在我们将其称为 foo details 该页面是从 bar details 链接的 因此 查看 bar details 您会看到链接
  • 如何使用 JSON_TABLE 从 Oracle JSON 列获取键值作为结果集

    我用谷歌搜索了很多 似乎无法找到适合我的简单用例的简单解决方案 我在 Oracle 12C 数据库中有一个 json 列 当然实际上是一个带有 json 约束的 varchar 在该列中我存储了这样的 Map 表示 a 9 0847 b 8
  • 检索 Steam 市场上物品的价格历史记录

    关于 Steam 市场上的物品 我想知道是否有办法检索某物品在一段时间内的价格历史记录 我知道 Steam 为想要将市场特定数据集成到自己网站中的开发人员提供了一个特殊的 api 但我还没有找到任何有关以 json 形式检索商品价格历史记录
  • 将 RequestBody json 转换为对象 - Spring Boot

    我是 java 开发的初学者 但之前有 PHP 和 Python 等编程语言的经验 对于如何进行 Spring Boot 的开发几乎没有什么困惑 我正在开发一个rest API 它有以下请求 key value key1 value1 pl
  • 清理 MongoDB 的输入

    我正在为 MongoDB 数据库程序编写 REST 接口 并尝试实现搜索功能 我想公开整个 MongoDB 接口 我确实有两个问题 但它们是相关的 所以我将它们放在一篇文章中 使用 Python json 模块解码不受信任的 JSON 是否
  • 用于一个自定义字段的 Jackson 反序列化器?

    我相信我们需要一个自定义反序列化器来对我们类中的一个字段执行特定的操作 看来一旦我这样做了 我现在就负责反序列化所有其他字段 有没有办法让杰克逊反序列化所有字段except我在这里关心的那个人 public class ThingDeser
  • 如何在 R 中解析堆叠多个 JSON 的文件?

    我在 R 中有以下 堆叠 JSON 对象 example1 json ID 12345 Timestamp 20140101 Usefulness Yes Code event1 A result 1 ID 1A35B Timestamp
  • 如何显示多维数组第二层的 json 值?

    解决此代码时遇到问题 这些是数组 Array 0 gt stdClass Object id gt 1 name gt delux price gt 213 description gt tv gt 0 breakfast gt 0 par
  • Rspec 控制器测试,传递 JSON 参数

    我试图实现以下目标 在 RSpec 控制器测试中创建 POST json 请求 并向其传递参数 这是我的代码 it returns access token do post login email bla password bla1 for
  • 将新属性动态添加到 Node 中现有的 JSON 数组中

    我需要添加当前 JSON 中不存在的属性 json 对象如下所示 var jsonObj result OK data 我想在 数据 中添加温度 我可以像下面那样做 jsonObj data push temperature 然后 我想在
  • 气流:如何将读取 json 文件的方法放入本地库中

    我必须产生一些DAG 我已将 json 表架构文件保存在GCP铲斗 https cloud google com storage docs json api v1 buckets GCP 存储桶上的文件关联到composer将被重新映射到

随机推荐

  • Apex类格式

    例子
  • 自动化测试之Selenium

    https www cnblogs com ldd215 p 5549984 html 文章目录 python常用操作 0 1 获取Excel中的数据 0 2 截取图片 第一章 第一讲 自动化测试概述 1 1什么是软件测试 1 2什么是自动
  • 【 力扣(LeetCode)刷题详细介绍】

    转载于 东心十 关于leetcode刷题详细介绍 虽然刷题一直饱受诟病 不过不可否认刷题确实能锻炼我们的编程能力 相信每个认真刷题的人都会有体会 现在提供在线编程评测的平台有很多 比较有名的有 hihocoder LintCode 以及这里
  • Google浏览器安装插件

    以安装 沙拉查词 插件为例 1 先点击Google浏览器右上方三个小点 找到 设置 将搜索引擎改为Bing 2 然后就可以使用新建页面了 在新建页面搜索 极简插件 或 扩展迷 搜索 沙拉查词 并下载 下载下来是一个压缩包 解压之后可以找到里
  • dnf安徒恩服务器不稳定,DNF安徒恩开团后掉线那些事 网友:这时才体会到混子的重要性...

    原标题 DNF安徒恩开团后掉线那些事 网友 这时才体会到混子的重要性 DNF安徒恩副本难度对于目前的玩家来说并不难 所以很多人追求极限人数开团 有时是12人 有时甚至是10人 于是问题来了 有人掉线怎么办 一起来看看大家在安徒恩的遭遇 玩家
  • 华为2018秋招笔试——将一段压缩后的字符串解压缩,并且排序输出

    题目描述 将一段压缩后的字符串解压缩 并且排序输出 解压规则 每个字符串后面跟随一个数字 表示这个字符串的重复次数 例如 a5 解压缩的结果为 aaaaa abc3 解压缩后的结果为 abcabcabc 排序规则 1 根据每个字符串的重复次
  • 详解拷贝构造函数

    基本规则 拷贝构造函数是一种特殊的构造函数 函数的名称必须和类名称一致 它必须的一个参数是本类型的一个引用变量 所以类中可以存在多个拷贝构造函数 编译器会自动生成默认构造函数 这个构造函数很简单 仅仅使用 老对象 的数据成员的值对 新对象
  • PyTorch(Python)训练MNIST模型移动端IOS上使用Swift实时数字识别

    识别手写数字是计算机视觉的基石问题 可以通过神经网络来解决 在此 我不会重复有关模型构建和训练的细节 本文中 我的目的是将经过训练的模型移植到移动环境中 我使用 pytorch 构建模型 因为我想尝试一下 torchscript 对于 io
  • 山东大学项目实训开发日志——基于vue+springboot的医院耗材管理系统(14)

    我们解决了一个逻辑上的问题 1 医院向供货商下单 如果供货商一时不能提供足够的数量 应该怎么办 2 科室库向中心库提交申请 如果中心库库存不满足申请的数量 应该怎么办 经过一番讨论 对于第一个问题 后端的负责人表示 应该有一个功能 允许供货
  • ESP8266-01S系列学习笔记-01模块基本知识

    1 产品概述 ESP8266是乐鑫科技生产的一款内置WiFi功能的单片机 它有很多种型号 这些型号分别对应了不同的封装 ESP8266是一款超低功耗的UART WiFi 透传模块 拥有业内极富竞争力的封装尺寸和超低能耗技术 专为移动设备和物
  • 【实战教程】在小程序中快速生成分享海报

    在小程序中生成分享海报是一个很常见的需求 目前主要有以下两种做法 直接由前端生成 使用小程序提供的 canvas API 由后端知晓云 云函数 生成 前端再获取 本文将介绍通过知晓云 云函数 来生成分享海报的功能 并使用 webpack 和
  • ElasticSearch学习笔记(4)· ES IK分词器

    目录 九 IK中文分词器 1 在线安装IK中文分词器 2 本地安装IK中文分词器 3 扩展词 4 停用词 5 配置远程词典 6 分词器总结 九 IK中文分词器 NOTE 默认ES中采用标准分词器进行分词 这种方式并不适用于中文网站 因此需要
  • 基于unity+高通AR项目的一些总结

    今天 公司做的第一款AR项目终于在苹果appstore上架了 将近三个多月的踩坑和摸索也终于告一段落了 接下来就是不断的进行版本优化和更新 这将是一个漫长的过程 在此 对自己三个多月的开发做一个阶段性的总结 也希望能够帮到一些正在用unit
  • 【算法图解】 之 [贪婪算法(贪心算法)] 详解

    入门算法学习 看的第一本是深入浅出的 算法图解 一书 本博客是对 算法图解 一书的学习笔记 将书中的分享的算法示例用Python3语言实现 如果你也想要阅读这本书 百度云盘链接 https pan baidu com s 1s967vfgE
  • Java企业级应用常采用哪些系统架构?

    架构 又名软件架构 是有关软件整体结构与组件的抽象描述 用于指导大型软件系统各个方面的设计 Java企业级的应用根据业务的复杂程度 通常使用的系统架构有应用架构 垂直应用架构 面向服务的架构 Service Oriented Archite
  • Mybatis 使用标签时遇到的一个问题与标签的使用

    欢迎访问本人博客查看原文 http wangnan tech 今天遇到一个场景需要写一个这样的查询语句 用户对象userInfo包含下面几个字段 userName phone email qqId weiboId wxId 现在新注册用户
  • 手把手带你入门深度学习(一):保姆级Anaconda和PyTorch环境配置指南

    手把手带你入门深度学习 一 保姆级Anaconda和PyTorch环境配置指南 一 前言和准备工作 1 1 python anaconda和pytorch的关系 二 Anconda安装 2 1 安装 anaconda 2 2 更改pip源和
  • 2021-04-26(全网最简单)Centos8安装最新版本RabbitMQ和erlang

    1 首先进入rabbitmq官网 找到如图所示位置 2 进入到下载和安装页面 找到安装向导 3 选择CentOS点进去 意思是说有两种方法可以安装最新版本的RabbitMQ 使用Package Cloud或Bintray上的Yum存储库安装
  • [483]tensorflow模型保存和读取tf.train.Saver

    目标 训练网络后想保存训练好的模型 以及在程序中读取以保存的训练好的模型 首先 保存和恢复都需要实例化一个 tf train Saver saver tf train Saver 然后 在训练循环中 定期调用 saver save 方法 向
  • 让木桶没有短板,FISCO BCOS全面推进区块链并行化改造

    FISCO BCOS是完全开源的联盟区块链底层技术平台 由金融区块链合作联盟 深圳 简称金链盟 成立开源工作组通力打造 开源工作组成员包括博彦科技 华为 深证通 神州数码 四方精创 腾讯 微众银行 亦笔科技和越秀金科等金链盟成员机构 代码仓