分布式轮对注册表:使用Hyperledger Fabric的经验

嗨,我在RRP KP(分布式数据寄存器,用于监视轮对的生命周期)的项目团队中工作。在这里,我想分享我们团队在技术条件下为该项目开发公司区块链的经验。在大多数情况下,我将讨论Hyperledger Fabric,但是这里描述的方法可以推断到任何许可的区块链上。我们研究的最终目标是准备企业区块链解决方案,以使最终产品使用起来愉快且维护起来不太困难。

这里不会有发现,意外的解决方案,也不会涵盖任何独特的发展(因为我没有它们)。我只想分享我的谦虚经验,以表明“有可能”,也许还可以在评论中阅读他人在做出明智决定时的经验。

问题:区块链尚未扩展


今天,许多开发人员的努力旨在使区块链成为一种真正方便的技术,而不是精美包装中的定时炸弹。状态通道,乐观汇总,血浆和分片可能每天都在发生。有一天或者,TON将再次推迟发射六个月,而下一个等离子集团将不复存在。我们可以相信另一份路线图,并在当晚阅读出色的白皮书,但是现在和现在,我们需要对已有的东西做些事情。干嘛

在当前项目中为我们的团队设定的任务总体上看起来像这样:许多实体达到数千个,不希望建立信任关系。有必要在DLT上构建这样的解决方案,该解决方案可以在没有特殊性能要求的普通PC上运行,并且提供的用户体验不会比任何集中式记帐系统差。解决方案的基础技术应将恶意操作数据的可能性降到最低,这就是为什么区块链在这里。

白皮书和媒体的口号向我们保证,下一个发展将使您每秒进行数百万笔交易。到底是什么

Mainnet以太坊现在的运行速度约为30 tps。正因为如此,很难将其视为适合企业需求的任何区块链。在许可的解决方案中,基准是已知的,显示的是2000 tps(Quorum)或3000 tps(Hyperledger Fabric,发布量要小一些,但是您需要考虑基准是在旧的共识引擎上执行的)。尝试对Fabric进行彻底的修改,该结果并没有给出最差的结果,20,000 TPS,但到目前为止,这只是学术研究在等待其稳定实施。一家有能力维持区块链开发人员部门的公司不太可能接受这样的指标。但是问题不仅在于吞吐量,还存在延迟。

潜伏


从交易开始到系统最终批准的延迟,不仅取决于通过验证和排序的所有阶段的消息的速度,还取决于块形成的参数。即使我们的区块链允许我们以1,000,000 tps的速度提交数据,但是形成488 MB的块需要10分钟,对我们来说会变得更容易吗?

让我们仔细看一下Hyperledger Fabric中的事务生命周期,以了解所花的时间以及它与块形成参数之间的关系。


取自此处hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html#swimlane

(1)客户端生成交易,将其发送给背书的对等方,后者对交易进行模拟(将链码所做的更改应用于当前状态,但不提交到分类账)并获取RWSet-从CouchDB中的集合中获取的键名,版本和值,( 2)背书人将签名的RWSet发送回客户端,(3)客户端要么检查所有必要对等方(背书人)的签名,然后将交易发送到订购服务,要么不经验证就将其发送(稍后将进行验证),订购服务构成一个块,并且( 4)发送回所有同行,不仅是背书人;对等方检查读取集中的密钥版本是否与数据库中的版本,所有背书者的签名匹配,最后提交该块。

但这还不是全部。 “订单形成一个块”一词不仅隐含了交易的顺序,而且还隐瞒了领导者对追随者的3个连续网络请求,反之亦然:领导者向日志中添加一条消息,发送给关注者,追随者将其添加到他的日志中,将成功复制的确认发送给领导者,领导者提交一条消息,将提交确认发送给关注者,关注者提交。块形成的大小和时间越小,订购服务就越需要建立共识Hyperledger Fabric具有两个块形成参数:BatchTimeout-块形成时间和BatchSize-块大小(事务数和块本身的大小(以字节为单位))。一旦参数之一达到极限,就会释放一个新块。担保节点越多,花费的时间就越长。因此,您需要增加BatchTimeout和BatchSize。但是,由于对RWSets进行了版本控制,我们制作的块越多,MVCC冲突的可能性就越高。另外,随着BatchTimeout的增加,UX灾难性地降级。在我看来,以下方案可以解决这些问题,这是合理而明显的。

避免等待块定稿,并且不要失去跟踪交易状态的能力


形成时间和块大小越长,区块链的吞吐量就越高。另一个没有直接遵循,但应该记住,在RAFT中建立共识需要从领导者到关注者三个网络请求,反之亦然。顺序节点越多,花费的时间就越长。嵌段的尺寸和形成时间越小,这种相互作用越多。如何在不增加最终用户等待系统响应时间的情况下增加编队时间和块大小?

首先,您需要以某种方式解决由大块大小引起的MVCC冲突,其中可能包括具有相同版本的不同RWSet。显然,在客户端(就区块链网络而言,这很可能是后端,我的意思是这样),您需要一个MVCC冲突处理程序,它可以是带有重试逻辑的事务触发调用上的单独服务或常规装饰器。

重试可以采用指数策略来实现,但是延迟会成指数下降。因此,您应该在一定的小范围内使用随机重试,或者永久使用。在第一实施例中着眼于可能的冲突。

下一步是使客户端与系统的交互异步,以使其不等待15、30或10,000,000秒,我们将其设置为BatchTimeout。但是同时,您需要保留机会,以确保将事务启动的更改写入/不写入区块链。
您可以使用数据库来存储事务状态。最简单的选择是CouchDB,因为它易于使用:数据库具有现成的UI,REST API,并且您可以轻松地为其配置复制和分片。您可以在Fabric用于存储其世界状态的同一CouchDB实例中仅创建一个单独的集合。我们需要存储这种文件。

{
 Status string //  : "pending", "done", "failed"
 TxID: string // ID 
 Error: string // optional,   
}


在将事务转移给对等方之前,将此文档写入数据库,如果此操作是创建操作,则将实体ID返回给用户(使用相同的ID作为密钥),然后在收到来自对等方的相关信息时更新Status,TxID和Error字段。



在此方案中,用户无需等待块最终形成,只需在屏幕上观察纺车10秒钟,他便会收到系统的即时响应并继续工作。

我们选择BoltDB来存储事务状态,因为我们需要节省内存,并且不想在与独立数据库服务器的网络交互上花费时间,尤其是在使用纯文本协议进行交互时。顺便说一下,您可以使用CouchDB实现上述方案,或者仅存储世界状态,无论如何,优化数据在CouchDB中的存储方式是有意义的。默认情况下,在CouchDB中,b树节点的大小为1279字节,比磁盘上的扇区大小小得多,这意味着读取和重新平衡树将需要更多的物理磁盘访问。最佳大小符合Advanced Format标准,为4 KB。为了进行优化,我们需要将btree_chunk_size参数设置为4096在CouchDB配置文件中。对于BoltDB,不需要这种手动干预

背压:缓冲策略


但是可能会有很多消息。该系统不仅具有处理能力,还可以与图中所示的其他服务共享资源,并且即使在启动Intellij Idea极其繁琐的机器上,所有这些功能也可以正常运行。

通信系统(生产者和消费者)的吞吐量不同的问题以不同的方式解决。让我们看看我们能做什么。

删除:我们可以声称能够在T秒内处理不超过X个事务。超过此限制的所有请求将被重置。这很简单,但是您可以忘记UX。

控制性:消费者应具有一些接口,通过该接口,根据负载,他将能够控制生产者的tps。不错,但是它对创建负载以实现此接口的客户端开发人员构成了义务。对于我们来说,这是不可接受的,因为将来区块链将被集成到大量长期存在的系统中。

缓冲:我们可以缓冲此数据流并以所需的速度对其进行处理,而不是试图抵抗输入数据流。显然,如果我们要提供良好的用户体验,这是最好的解决方案。我们使用RabbitMQ中的队列实现了缓冲区。



方案中添加了两个新操作:(1)在收到对API的请求后,将包含调用事务所需参数的消息排队,并且客户端收到消息,表明系统已接受该事务,(2)后端以配置中指定的速度读取数据从队列中 启动事务并更新状态存储中的数据。
现在,您可以随意增加编队时间并增加封堵能力,从而避免了用户的延迟。

其他工具


这里没有说关于链码,因为通常来说,没有什么要优化的。Chaincode应该尽可能简单和安全-这就是它所需要的。Cheynkod简单的写和安全地帮助我们大大框架SSKit从S7 Techlab和静态分析复兴^ CC

此外,我们的团队正在开发一套实用程序,以使使用Fabric变得简单而愉快:区块链浏览器,一种用于自动更改网络配置的实用程序(添加/删除组织,RAFT节点),一种用于吊销证书和删除身份的实用程序如果您想贡献-欢迎。

结论


这种方法可以轻松地用Quorum,其他专用的以太坊网络(PoA甚至PoW)替换Hyperledger Fabric,显着降低实际带宽,但同时保持正常的UX(对于浏览器和集成系统中的用户而言)。在方案中用以太坊替换Fabric时,您只需要将重试服务/装饰器的逻辑从处理MVCC冲突更改为原子增量随机数并重新发送。缓冲和状态存储允许将响应时间与块形成时间分开。现在,您可以添加成千上万的订购节点,而不必担心块形成过于频繁并加载订购服务。

总的来说,这就是我要分享的全部。如果这对某人的工作有所帮助,我将感到高兴。

All Articles