14个版本
0.2.41-beta.14 | 2024年7月2日 |
---|---|
0.2.41-beta.12 | 2024年4月17日 |
0.2.41-beta.11 | 2024年2月24日 |
0.2.41-beta.8 | 2023年12月12日 |
0.2.41-beta.4 | 2023年7月22日 |
#221 in 异步
48 每月下载次数
用于 4 个Crates(通过 zebra-consensus)
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