14个版本

0.2.41-beta.142024年7月2日
0.2.41-beta.122024年4月17日
0.2.41-beta.112024年2月24日
0.2.41-beta.82023年12月12日
0.2.41-beta.42023年7月22日

#221 in 异步

48 每月下载次数
用于 4 个Crates(通过 zebra-consensus

MIT 协议

44KB
654

Tower中间件,用于批量请求处理

此包提供处理批量处理延迟/吞吐量权衡的通用中间件。它提供了一个具有 BatchControl<R> 枚举和 Item(R) 以及 Flush 变体的 Batch<S> 包装器,该包装器封装 S: Service<BatchControl<R>> 以提供 Service<R>,管理最大请求延迟和批量大小。

示例:批量验证

在密码学中,批量验证询问某个集合中的所有项目是否有效,而不是询问每个项目是否有效。这通过允许跨每个项目共享计算来提高吞吐量。然而,这以更高的延迟(整个批次必须完成)为代价,增加了调用者代码的复杂性(必须组装要验证的项目批次),并且失去了轻松定位失败项目的功能(需要重试或更复杂的技术)。

延迟与吞吐量之间的权衡是可管理的,但第二个方面带来了严重的实际困难。传统的批量验证API需要提前选择要批量处理的数据量,然后同时处理整个批次。但对于需要验证异构数据的应用程序,这既繁琐又困难。

例如,Zcash使用四种不同类型的签名(来自比特币的ECDSA签名,Sprout的Ed25519签名,以及Sapling的RedJubjub花费验证和绑定签名)以及三种不同类型的零知识证明(Sprout-on-BCTV14,Sprout-on-Groth16和Sapling-on-Groth16)。一个交易可以有多种不同类型的证明或签名,这取决于交易版本及其结构。交易的传统验证过程是“深度优先”,首先检查结构是否适当,然后检查所有组成部分的签名和证明是否有效。

现在考虑在这个环境中实现批量验证的问题,使用需要传递签名或证明列表的传统批量验证API。这相当复杂,需要实现一套“广度优先”的验证逻辑,在组装签名和证明集合以验证的同时检查每个交易的适当性。这种转置的验证逻辑必须与未转置的逻辑匹配,但还有一个问题,即必须提前决定交易集。这很困难,因为不同的上下文需要不同级别的批量处理。例如,在收到八卦交易时进行交易内的批量处理是合适的,在块验证时进行块内的批量处理是合适的,在同步链时进行跨块的批量处理是合适的。

异步批量验证

为了解决这个问题,我们将签名验证的同步模型转变为异步模型。验证不是立即返回验证结果,而是返回一个最终将解析为验证结果的future。验证future可以与各种future组合器结合使用,表达组合验证检查的逻辑语义。这允许编写泛型检查,这些检查可以针对单例或批量验证进行选择。并且因为批量上下文与验证逻辑本身是不同的,所以相同的验证逻辑可以在不同的批量上下文中重用——在交易内、在块内、在链内等。

批量处理中间件

Tower的Service接口是实施这种模型的一个有吸引力的选择,原因有两个。首先,它使得对Service的泛型界限表达变得容易,允许编写泛型的高层验证服务,这些服务可以针对每个低层组件的验证进行泛型编写。

其次,Tower的设计允许服务组合器轻松地组合行为。例如,上述第三个缺点(故障定位)可以通过组合一个批量验证Service和一个重试Layer来解决,该重试Layer在不批量处理的情况下重试验证该项目。

需要解决的问题剩余是延迟与吞吐量的权衡。管理这种权衡的逻辑与特定的批量处理过程无关,并且这个crate提供了一个通用的Batch包装器来实现这一点。包装器使用一个包含Item(R)Flush变体的BatchControl<R>枚举。给定S: Service<BatchControl<R>>Batch<S>包装器提供了一个Service<R>。包装的服务不需要实现任何批量控制逻辑,因为它将从包装器接收到显式的Flush请求。

实现历史

tower-batch-control代码修改自2019年版本的:[https://github.com/tower-rs/tower/tree/master/tower/src/buffer](https://github.com/tower-rs/tower/tree/master/tower/src/buffer)

这个crate的修改分支可在crates.io上以tower-batch的形式找到。它专注于批量磁盘写入。

依赖项

~5–7.5MB
~124K SLoC