轮对的分布式注册表:Hyperledger Fabric 的体验

你好,我在DRD KP项目(用于监控轮对生命周期的分布式数据注册中心)团队工作。 在这里我想分享一下我们团队在技术限制下为这个项目开发企业区块链的经验。 在很大程度上,我将讨论 Hyperledger Fabric,但这里描述的方法可以推断到任何许可的区块链。 我们研究的最终目标是准备企业区块链解决方案,使最终产品易于使用且维护起来不太困难。

这里不会有任何发现、意想不到的解决方案,也不会涵盖任何独特的发展(因为我没有它们)。 我只是想分享我卑微的经验,表明“这是可能的”,也许,在评论中阅读其他人做出好的和不太好的决定的经验。

问题:区块链尚不可扩展

如今,许多开发人员的努力旨在使区块链成为一种真正方便的技术,而不是一个漂亮包装中的定时炸弹。 状态通道、乐观汇总、等离子和分片可能会变得司空见惯。 有一天。 或者也许 TON 将再次推迟发布六个月,而下一个 Plasma Group 将不复存在。 我们可以相信另一个路线图并在晚上阅读精彩的白皮书,但此时此地我们需要利用我们所拥有的东西做点什么。 搞定吧。

当前项目中分配给我们团队的任务大致是这样的:有很多主体,达到数千人,他们不想建立信任关系; 有必要在DLT的基础上构建一个可以在普通PC上运行、没有特殊性能要求的解决方案,并提供不比任何中心化记账系统差的用户体验。 该解决方案背后的技术应该最大限度地减少恶意数据操纵的可能性——这就是区块链出现的原因。

白皮书和媒体的口号向我们承诺,下一步的发展将允许每秒数百万笔交易。 到底是什么?

以太坊主网目前的运行速度约为 30 tps。 仅凭这一点,就很难将其视为一种适合企业需求的区块链。 在许可的解决方案中,已知显示 2000 tps 的基准测试(法定人数) 或 3000 tps (超重织物,出版物中的内容有点少,但请记住,基准测试是在旧的共识引擎上进行的)。 曾是 尝试从根本上改造 Fabric,它给出的结果并不是最差的,20000 tps,但到目前为止这些还只是等待稳定实施的学术研究。 有能力维持区块链开发人员部门的公司不太可能容忍这样的指标。 但问题不仅在于吞吐量,还存在延迟。

潜伏

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

让我们仔细看看 Hyperledger Fabric 中事务的生命周期,以了解什么需要时间以及它与块形成参数的关系。

轮对的分布式注册表:Hyperledger Fabric 的体验
取自这里: hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html#swimlane

(1) 客户端形成一个交易,将其发送给背书节点,背书节点模拟交易(将链码所做的更改应用到当前状态,但不提交到账本)并接收 RWSet - 密钥名称、版本和从 CouchDB 中的集合中获取的值,(2) 背书者将签名的 RWSet 发送回客户端,(3) 客户端检查所有所需节点(背书者)的签名,然后将交易发送到排序服务,或者在没有验证的情况下发送(验证仍将在稍后进行),排序服务形成一个块并且(4)发送回所有节点,而不仅仅是背书者; 节点检查读取集中的密钥版本是否与数据库中的版本、所有背书者的签名相匹配,最后提交该块。

但这还不是全部。 “orderer 形成区块”这句话背后不仅隐藏着交易的排序,还隐藏着从leader到follower并返回的连续3次网络请求:leader向日志添加一条消息,发送给follower,后者添加到他们的日志,向领导者发送成功复制的确认,领导者提交消息,向追随者发送提交确认,追随者提交。 区块大小和时间越小,排序服务就越需要建立共识。 Hyperledger Fabric 有两个区块形成参数:BatchTimeout - 区块形成时间和 BatchSize - 区块大小(交易数量和区块本身的大小(以字节为单位))。 一旦其中一个参数达到限制,就会发出一个新块。 订购者节点越多,花费的时间就越长。 因此,需要增加BatchTimeout和BatchSize。 但由于 RWSets 是版本化的,我们制作的块越大,MVCC 冲突的可能性就越高。 此外,随着 BatchTimeout 的增加,UX 会发生灾难性的下降。 在我看来,解决这些问题的以下方案是合理且明显的。

如何避免等待区块最终确定并且不丢失交易状态

形成时间和区块大小越长,区块链的吞吐量就越高。 一个并不直接跟随另一个,但应该记住,在 RAFT 中建立共识需要从领导者到追随者的三个网络请求并返回。 订单节点越多,花费的时间就越长。 区块形成的大小和时间越小,这种相互作用就越多。 如何在不增加最终用户系统响应时间的情况下增加形成时间和块大小?

首先,您需要以某种方式解决由大块大小引起的 MVCC 冲突,其中可能包含具有相同版本的不同 RWSets。 显然,在客户端(相对于区块链网络,这很可能是后端,我是认真的) MVCC 冲突处理程序,它可以是一个单独的服务,也可以是带有重试逻辑的事务启动调用上的常规装饰器。

重试可以采用指数策略来实现,但延迟也会呈指数下降。 因此,您应该在一定的小限制内使用随机重试,或者使用恒定重试。 着眼于第一个变体中可能发生的碰撞。

下一步是使客户端与系统的交互异步,这样就不会等待 15、30 或 10000000 秒,我们将其设置为 BatchTimeout。 但同时,需要保留确保交易发起的更改被记录/不记录在区块链中的能力。
数据库可用于存储事务的状态。 最简单的选择是 CouchDB,因为它易于使用:该数据库具有开箱即用的 UI、REST API,并且您可以轻松地为其设置复制和分片。 您可以在 Fabric 用于存储其世界状态的同一个 CouchDB 实例中创建一个单独的集合。 我们需要存储此类文档。

{
 Status string // Статус транзакции: "pending", "done", "failed"
 TxID: string // ID транзакции
 Error: string // optional, сообщение об ошибке
}

该文档在交易发送给对等方之前写入数据库,如果这是创建操作,则将实体 ID 返回给用户(使用相同的 ID 作为键),然后是 Status、TxID 和 Error 字段当从同行收到相关信息时进行更新。

轮对的分布式注册表:Hyperledger Fabric 的体验

在这个方案中,用户不用等待区块最终形成,只要观看屏幕上旋转的轮子10秒,他就会收到系统的即时响应并继续工作。

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

背压:缓冲策略

但可能会有很多消息。 除了图中所示的服务之外,还与十几个其他服务共享资源,这超出了系统的处理能力——即使在运行 Intellij Idea 极其乏味的机器上,所有这些都应该可以完美地工作。

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

删除:我们可以声称能够在 T 秒内处理最多 X 笔交易。 所有超过此限制的请求都会被丢弃。 这非常简单,但是您可以忘记用户体验。

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

缓冲:我们可以缓冲该流并以所需的速度处理它,而不是设法阻止输入数据流。 显然,如果我们想提供良好的用户体验,这是最好的解决方案。 我们使用 RabbitMQ 中的队列实现了缓冲区。

轮对的分布式注册表:Hyperledger Fabric 的体验

该方案中添加了两个新操作:(1)收到 API 请求后,一条消息将与调用交易所需的参数一起排队,并且客户端收到一条消息,表明该交易已被系统接受,( 2)后端以配置中指定的速度从队列中读取数据; 发起事务并更新状态存储中的数据。
现在,您可以根据需要增加构建时间和块容量,从而向用户隐藏延迟。

其他工具

这里没有提及链码,因为它通常没有什么可以优化的。 链码应该尽可能简单和安全——这就是它所需要的全部。 该框架对我们简单安全地编写链代码有很大帮助。 CSKit 来自 S7 Techlab 和静态分析仪 复活^CC.

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

结论

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

总的来说,这就是我想分享的全部。 如果它对某人的工作有帮助,我会很高兴。

来源: habr.com

添加评论