抽象的
以太坊正在通过逐步提高The Blockgas 上限来扩容 L1 缓存。然而,大幅提高 gas 上限(例如Dankrad 提出的 100 倍提升方案)会迅速触及磁盘 I/O 和 CPU 执行速度的瓶颈。预热和EIP-7928 区块级访问控制列表 (BAL)可以消除大部分 I/O 读取阻塞,将主要瓶颈转移到执行本身。与此同时,现有客户端仍然按顺序执行交易,从根本上限制了吞吐量。
BAL ( 我们团队两年前也探索过这个想法)实现了完美的并行执行,但其性能上限仍不明确。为了解决这个问题,我们构建了一个纯执行环境,其中包含:
- 预加载状态,模拟相关账户、存储槽位和合约代码通过BAL提示预先解析的环境;
- 预先恢复的发送方,利用大多数客户端中已实现的并行发送方恢复功能;
- 省略状态根计算,其成本可以分摊到更大的块中。
在此环境下,我们使用BAL对每事务并行执行进行了基准测试。结果表明,在现代 16 核商用 PC 上,纯执行吞吐量超过10 GigaGas/s ,而当前 Reth 客户端在相同条件下仅能达到约 1.2 GigaGas/s。这表明,一旦上述瓶颈得到彻底解决,EVM 执行能力可以比当前客户端基准性能提升一个数量级。
我们今天所处的位置
以太坊在 Fusaka 升级中将 gas 上限从 4500 万提升至 6000 万。假设 gas 上限提升 100 倍,则生成的区块将包含约 4.5 吉 gas。为了将验证时间控制在三秒以内,验证者至少需要 1.5 吉 Gas/s 的执行吞吐量。然而, Base 的公开基准测试表明,在普通硬件上运行的现代客户端最高只能达到约 600 吉 Gas/s。这一限制主要源于顺序执行:尽管多核 CPU 已经可用,但现有客户端仍然采用串行方式处理交易,导致大多数核心未得到充分利用。
| 发射有效载荷 | Geth MGas/s | Reth MGas/s |
|---|---|---|
| 基础主网模拟 | 316.4 | 591.6 |
当前性能(~0.6 GGas/s)与 100 倍扩展所需的性能(~1.5 GGas/s)之间的差距仍然很大——这促使我们努力实现完全并行的 EVM 执行。
我们是如何做到的
为了研究BAL带来的极致并行执行性能,我们构建了一个纯执行环境,移除了所有无关的非执行部分,从而能够测量 BAL 并行性的真正上限。利用 Rust 的无垃圾回收设计、对多线程调度的细粒度控制以及 Reth 的高性能,我们修改了 Reth 客户端,并使用 revm 作为 EVM 执行引擎进行本次实验。
纯粹执行仿真的简化
- 整个链状态预先加载到内存中(因为我们可以根据 BAL 的读取位置进行批量 I/O)。
- 所有交易都已恢复发送方身份(发送方恢复可以事先完全并行化)。
- 执行后不会进行状态根计算和数据库提交(这是一个瓶颈,但不是本研究的主要重点)。
工程工作及搭建
- 修改了 Reth 客户端,使其支持转储完整的执行依赖项,包括块、BAL、最后 256 个块哈希以及从BAL读取集提示解析的块前状态。
- 为 Revm 添加了一个适配器,用于加载
blockEnv、state和txEnv,并为每个交易创建一个单独的 EVM 实例。 - 并行粒度 =按事务。
- 硬件:AMD Ryzen 9 5950X(16 核),128 GB 内存。
- 数据集:2000 个主网区块(
#23600500–23602500)。 - 指标:每秒 Gas 消耗量 = 总 Gas 消耗量 / 纯执行模拟时间。
基准测试套件可在此处获取:
https://github.com/dajuguan/evm-benchmark
结果
我们的评估首先针对revm的顺序执行性能进行了校准,然后逐步引入并行执行。并行扩展性分析表明,运行时间最长的交易的延迟是限制整体加速的关键路径。为了缓解这一限制,我们模拟了更高的区块gas限制,从而显著提升了BAL的并行性。在16个线程和1G区块gas限制下,纯执行吞吐量达到了约14 GGas/s 。
基线对齐与顺序执行
我们首先尝试复现 Reth 的基准测试结果。在预加载 KZG 设置的情况下,对主网数据进行顺序运行,纯执行速度达到了 1,212 MGas/s。
这一连续结果将作为我们后续所有实验的参考点。
并行执行及其关键路径瓶颈
为了评估实际加速效果以及阿姆达尔定律对事务级并行性的影响,我们进行了逐事务并行执行实验,以量化运行时间最长的事务对可实现加速效果的影响。
详细结果如下所示(其中“最长交易延迟”是指每个区块中运行时间最长的交易的总执行时间):
| 线程 | 吞吐量(百万燃气/秒) | 最长传输延迟 | 总时间 |
|---|---|---|---|
| 1 | 1258 | 6.06秒 | 33.47秒 |
| 2 | 2460 | 6.04秒 | 17.12秒 |
| 4 | 3753 | 6.10秒 | 10.71秒 |
| 8 | 4824 | 6.00秒 | 8.73秒 |
| 16 | 5084 | 6.04秒 | 8.29秒 |
总体而言,扩展性测试结果与阿姆达尔定律高度吻合:虽然吞吐量随着线程数的增加而提高,但块执行时间受限于最长事务,在16个线程的情况下,最长事务约占总执行时间的70%,这使得可实现的加速比上限约为5倍,而非16核机器的理想16倍。这表明,可扩展性取决于每个块的关键路径,而非原始计算能力。
可以通过降低最长交易的主导地位来缓解这种关键路径限制,例如通过EIP-7825:交易 gas 限制上限或增加区块 gas 限制——本文探讨的方法。
7928 + 巨型模块 = 大规模并行
由于每个区块的关键路径限制了并发性,我们尝试使用更高 gas 费用的“巨型区块”来提高并行性。为了模拟这种情况,我们并行执行了多个连续主网区块(即巨型区块或批次)的交易,并在批次中的所有交易完成后才提交状态(实验中为空操作)。这有效地将多个区块聚合为一个大型执行单元。
超大规模工作负载下的并行性分析
我们首先评估了 50 个代码块,模拟了不同线程数下平均代码块 gas 消耗量为 1,053 M 的情况。完整结果如下所示:
| 线程 | 吞吐量(百万燃气/秒) | 最长传输延迟 | 总时间 |
|---|---|---|---|
| 1 | 1,440 | 0.50秒 | 29.26秒 |
| 2 | 2,793 | 0.50秒 | 15.08秒 |
| 4 | 5,167 | 0.52秒 | 8.15秒 |
| 8 | 9,095 | 0.54秒 | 4.63秒 |
| 16 | 14,001 | 0.59秒 | 3.01秒 |
由于区块尺寸如此之大,运行时间最长的交易不再主导关键路径——在 16 个线程下,它们仅占总执行时间的不到 20%。吞吐量几乎与线程数呈线性关系:使用 16 个线程,我们实现了 14 GGas/s 的吞吐量,比顺序执行快了大约 10 倍,接近理想的线性扩展。这令人非常鼓舞。在我们的实验中,唯一剩下的主要关键路径是point_evaluation预编译,而这部分难以轻易并行化。
不同模块气体利用率下的吞吐量
为了评估并行执行如何随着区块 gas 使用量的增加而扩展,我们执行了连续区块批次,同时改变了The Block批次大小(即分组到一个大型区块中的区块数量),从而模拟了不同的有效区块 gas 使用量。
| 线程 | 块批次大小 | 平均块状气体(M) | 吞吐量(百万燃气/秒) |
|---|---|---|---|
| 16 | 1 | 21 | 5,084 |
| 16 | 2 | 42 | 6,641 |
| 16 | 5 | 105 | 8,814 |
| 16 | 10 | 210 | 10,228 |
| 16 | 25 | 526 | 12,152 |
| 16 | 50 | 1,053 | 14,001 |
| 16 | 100 | 2,106 | 14,887 |
| 16 | 200 | 4,212 | 15,298 |
随着The Block气使用量的增加,吞吐量持续提升,但并行度的增量提升却从每增加一倍块气所对应的约 30% 下降到约 3%。一旦批处理大小超过约 50 个块(约 10.53 亿块气),进一步增加块气带来的吞吐量提升微乎其微。
前景
我们的实验表明,将EIP-7928 与巨型区块相结合,能够显著提升交易执行的可扩展性,在现代 16 核通用处理器上实现了14 GigaGas/s 的纯执行吞吐量。然而,仍有几个问题尚未解决:
1. 发件人恢复
我们在纯执行基准测试中排除了发送方恢复。在我们的实验中,启用发送方恢复会使吞吐量降低约 2/3,在巨型块配置(10.53 亿块 gas)下降至约 5 GigaGas/s。
可能的缓解措施:GPU加速的发送方恢复。
2. 天然气定价模型
7702 交易的point_evaluation预编译和发送方恢复功能效率较低,其 gas 消耗效率也较低。在 EIP-7928 时代,可能需要重新评估其 gas 定价机制。
3. 交易 Gas 限额
提高区块 gas 限制可能需要保留当前的交易 gas 限制上限,以维持高并行性。
4. 加快BAL建设
构建器性能预计将成为主要瓶颈。提高BAL构建效率对于跟上纯执行吞吐量至关重要。
5. 优化状态提交
状态提交是另一个主要瓶颈。加快状态根计算速度和优化 trie 树提交对于维持高吞吐量执行至关重要。
其他作品
我们也探索了不同的任务调度策略,例如,根据 gas 消耗量或 gas 上限对高 gas 交易进行排序以提升优先级,以及简单的有序列表调度器 (OLS),其中交易保持自然区块顺序,并将每个新交易分配给第一个可用的核心。然而,当应用于主网数据时,对高 gas 交易进行优先级排序仅带来了微小的性能提升,并未显著影响整体吞吐量。
不同调度策略下的吞吐量
为了评估对整体吞吐量的影响,我们将优先调度高 gas 交易(按 gas 使用量或 gas 限制)与 OLS 进行了比较。
- 普通块体上的结果:
| 线程(调度器) | 吞吐量(百万燃气/秒) | 最长传输延迟 | 总时间 |
|---|---|---|---|
| 2(用气量) | 2,726 | 5.70秒 | 15.45秒 |
| 2(气体限制) | 2,728 | 5.68秒 | 15.44秒 |
| 2(OLS) | 2,460 | 6.04秒 | 17.12秒 |
| 4(用气量) | 4,401 | 6.09秒 | 9.57秒 |
| 4(气体限制) | 4,321 | 6.18秒 | 9.75秒 |
| 4(OLS) | 3,753 | 6.10秒 | 10.71秒 |
| 8(用气量) | 5,455 | 6.15秒 | 7.72秒 |
| 8(气体限制) | 5,426 | 6.13秒 | 7.76秒 |
| 8(OLS) | 4,824 | 6.00秒 | 8.73秒 |
| 16(用气量) | 5,643 | 6.03秒 | 7.47秒 |
| 16(气体限制) | 5,531 | 6.05秒 | 7.62秒 |
| 16(OLS) | 5,084 | 6.04秒 | 8.28秒 |
- 平均区块气体量为 1053M 的巨型区块的测试结果:
| 线程(调度器) | 吞吐量(百万燃气/秒) | 最长传输延迟 | 总时间 |
|---|---|---|---|
| 2(气体限制) | 2,732 | 0.53秒 | 15.42秒 |
| 2(OLS) | 2,793 | 0.50秒 | 15.08秒 |
| 4(气体限制) | 5,114 | 0.54秒 | 8.24秒 |
| 4(OLS) | 5,167 | 0.52秒 | 8.15秒 |
| 8(气体限制) | 9,082 | 0.57秒 | 4.64秒 |
| 8(OLS) | 9,095 | 0.54秒 | 4.63秒 |
| 16(气体限制) | 14,181 | 0.63秒 | 2.97秒 |
| 16(OLS) | 14,001 | 0.59秒 | 3.01秒 |
Toni 的分析表明,在最坏的情况下,优先处理高 gas 消耗的交易可以比 OLS 算法提升 20% 到 80% 的性能。然而,在实际应用中,使用真实的主网数据(代表平均情况)时,性能提升仅为 10% 左右,而且按 gas 限制、gas 使用量或 OLS 进行调度之间的差异微乎其微。在大型区块上,OLS 算法的性能几乎与基于 gas 限制的调度算法完全相同。这些观察结果表明,交易调度并非主要瓶颈;相反,主网交易的固有分布才是关键路径。


