Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
网络与协议指南12 分钟阅读

Base RPC 延迟:测量、OP-Stack 因素与查询速度优化

了解如何测量 Base RPC 延迟,理解 OP-Stack 因素如出块时间和 L1 结算,并通过实用技术优化查询速度。

TL;DR

Base RPC 延迟主要受地理距离、端点饱和度和 OP-Stack 数据路径影响。本指南介绍如何使用可复现脚本测量延迟,并通过 WebSocket 订阅、批处理、缓存和分页优化查询速度。

什么决定了 Base RPC 延迟?

Base RPC 延迟是发送 JSON-RPC 请求到接收响应之间的时间。它不是一个单一数字;它因方法、端点、区域和网络条件而异。主要因素包括到端点的地理距离、共享公共端点的饱和度以及 OP-Stack 数据路径(op-node 和 op-reth)。Base 约 2 秒的出块时间也为轮询或订阅设定了现实节奏。

对于大多数应用,您体验到的延迟是网络往返时间(RTT)和服务器处理时间的组合。另一个大陆的公共端点可能增加 100-200 毫秒的 RTT,而饱和的端点可能增加数秒的排队时间。理解这些因素有助于您选择合适的端点并优化查询。

地理距离通常是最明显的组成部分。当您的客户端在欧洲而 RPC 服务器在北美时,每个请求至少产生一次跨大西洋往返。在 TCP 协议下,仅握手就增加一个 RTT,TLS 又增加一个。对于典型的 HTTPS JSON-RPC 调用,在发送请求体之前至少需要两个 RTT。这就是为什么地理分布式端点或边缘缓存可以显著降低感知延迟。

端点饱和度是第二个主要因素。像免费提供商提供的公共端点被数千用户共享。当需求激增时,请求在服务器的连接池中排队,有效延迟可能从几十毫秒膨胀到几秒。速率限制(HTTP 429)是常见症状。专用端点,如 OnFinality 的 API 服务 提供的端点,将资源专用于您的工作负载,提供一致的性能。

OP-Stack 数据路径是第三个支柱。Base 运行 op-node(共识)和 op-reth(执行)。当您发送 JSON-RPC 请求时,它被路由到适当的组件。对于状态读取如 eth_call 或 eth_getBalance,op-reth 查询其本地数据库。数据库针对快速读取进行了优化,但重查询如跨大范围区块的 eth_getLogs 仍可能需要数百毫秒或更长时间。op-node 还与 L1(以太坊)同步以获取数据可用性和最终性,这影响数据的新鲜度。

方法权重是第四个常被低估的因素。像 eth_blockNumber 或 eth_chainId 这样的轻量方法从内存中提供,在健康节点上返回时间低于 10 毫秒。像 eth_getLogs 或 eth_getProof 这样的重量级方法可能花费数量级更长的时间,因为它们扫描大量数据。Base JSON-RPC 方法文档 列出了可用方法及其参数,但未指定性能特征。您必须自己测量它们。

  • 地理距离:客户端与 RPC 端点之间的物理距离直接影响网络 RTT。使用地理分布式端点以最小化此影响。
  • 端点饱和度:公共端点是共享的;其他人的大量使用可能导致排队和速率限制。专用端点提供一致的性能。
  • OP-Stack 数据路径:Base 使用 op-node(共识)和 op-reth(执行)。请求由 op-reth 处理,它从本地数据库读取。L1 结算影响最终性和数据新鲜度。
  • 方法权重:像 eth_blockNumber 这样的轻量方法很快;像跨大范围 eth_getLogs 这样的重量级方法很慢。明智地选择方法。

OP-Stack 架构及其对延迟的影响

Base 是一个 OP-Stack L2,出块时间约 2 秒。该堆栈将共识(op-node)和执行(op-reth)分离。当您发送 JSON-RPC 请求时,它到达 op-node(或如果使用执行端点则直接到达 op-reth),它根据本地状态处理请求。op-node 还与 L1(以太坊)同步以获取数据可用性和最终性。

L1 结算影响数据的新鲜度。Base 区块在短暂延迟后被视为“安全”,但仅在 L1 确认后才“最终化”。如果您的应用需要最终化数据,您可能需要等待更长时间,这增加了有效延迟。对于实时应用,您可以使用“安全”或“最新”区块,但要注意重组风险。

约 2 秒的出块时间意味着新区块频繁产生。每 2 秒轮询 eth_blockNumber 是合理的,但 WebSocket 订阅(eth_subscribe)对于实时更新更高效,因为它们推送事件而无需轮询开销。

op-node 维护 L2 链的视图,并与 L1 通信以获取存款信息和批次数据。当您按编号请求区块时,op-node 可能需要验证该区块是否规范。这种验证通常很快,但在 L1 拥塞时,可能会增加延迟。对于大多数用例,执行层是瓶颈,而不是共识层。

执行层 op-reth 使用针对以太坊风格工作负载优化的自定义数据库布局。它将状态存储为 Merkle Patricia Trie,但针对快速读取进行了优化。然而,某些操作,如遍历日志,需要扫描区块和解码收据。成本随区块数量和日志数量而扩展。例如,对包含热门合约的 10,000 个区块进行 eth_getLogs 查询可能返回兆字节数据并花费数秒。

要理解完整的数据路径,考虑典型的 eth_getBalance 调用。请求到达 RPC 端点,转发到 op-node。op-node 识别区块号(例如“最新”)并将请求传递给 op-reth。op-reth 在其数据库中查找账户状态,这可能涉及读取 Merkle 树的多个节点。然后结果被序列化并发送回去。每一步增加微秒到毫秒,但网络 RTT 对远程客户端占主导地位。

  • L1 结算:“安全”区块可快速获得,但“最终化”区块需要 L1 确认,增加延迟。
  • 出块时间:约 2 秒意味着新区块频繁;使用 WebSocket 订阅以避免轮询开销。
  • 执行层:op-reth 处理状态读取;像 eth_getLogs 这样的重查询可能很慢。
  • 共识层:op-node 与 L1 同步;在 L1 拥塞时,验证可能增加延迟。

如何测量 Base RPC 延迟:可复现脚本

要准确测量延迟,您需要一个脚本,测试多种方法并测量顺序和并发性能。以下 Node.js 脚本使用内置的 fetch API(Node 18+)向给定端点发送 JSON-RPC 请求。它测量 eth_chainId、eth_blockNumber、eth_getBalance、eth_getLogs 和 eth_call 的延迟。使用 node measure-latency.js <RPC_URL> 运行。

此脚本是测量指南,不是供应商基准。结果因区域、端点和网络条件而异。填写下面的结果表以比较端点。

脚本使用 process.hrtime.bigint() 进行高分辨率计时。它依次为每个方法发送单个请求,然后为每个方法发送 5 个并行请求以测量并发性。输出包括 HTTP 状态码和响应体的前 100 个字符,有助于诊断错误。

为了更稳健的测量,您应该在一天中的不同时间、不同区域多次运行脚本。您还可以修改脚本以测试 WebSocket 连接或为 eth_getLogs 使用特定区块号。关键是保持方法的一致性,以便比较有意义。

在解释结果时,请注意对新端点的第一个请求可能因 DNS 解析和 TLS 握手而较慢。建议在测量前通过发送几个请求来预热连接。脚本不会自动执行此操作,但您可以根据需要添加预热循环。

// measure-latency.js
const url = process.argv[2];
if (!url) { console.error('Usage: node measure-latency.js <RPC_URL>'); process.exit(1); }

const methods = [
  { name: 'eth_chainId', params: [] },
  { name: 'eth_blockNumber', params: [] },
  { name: 'eth_getBalance', params: ['0x0000000000000000000000000000000000000000', 'latest'] },
  { name: 'eth_getLogs', params: [{ fromBlock: '0x0', toBlock: '0x10', address: '0x0000000000000000000000000000000000000000' }] },
  { name: 'eth_call', params: [{ to: '0x0000000000000000000000000000000000000000', data: '0x' }, 'latest'] }
];

async function measure(method, params) {
  const start = process.hrtime.bigint();
  const res = await fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params })
  });
  const end = process.hrtime.bigint();
  const ms = Number(end - start) / 1e6;
  const text = await res.text();
  return { ms, status: res.status, body: text.slice(0, 100) };
}

async function sequential() {
  console.log('Sequential measurements:');
  for (const m of methods) {
    const r = await measure(m.name, m.params);
    console.log(`${m.name}: ${r.ms.toFixed(2)} ms (HTTP ${r.status})`);
  }
}

async function concurrent() {
  console.log('\nConcurrent measurements (5 parallel requests per method):');
  for (const m of methods) {
    const times = await Promise.all(Array(5).fill().map(() => measure(m.name, m.params)));
    const avg = times.reduce((a, b) => a + b.ms, 0) / times.length;
    console.log(`${m.name}: avg ${avg.toFixed(2)} ms`);
  }
}

sequential().then(concurrent).catch(err => { console.error(err); process.exit(1); });

// Expected output shape:
// Sequential measurements:
// eth_chainId: 12.34 ms (HTTP 200)
// eth_blockNumber: 15.67 ms (HTTP 200)
// ...
// Concurrent measurements (5 parallel requests per method):
// eth_chainId: avg 13.45 ms
// ...

结果表:填写您的测量数据

使用下面的表格记录您对不同端点和区域的测量结果。这有助于您比较提供商并为工作负载选择最佳提供商。请记住,结果因一天中的时间和网络条件而异。

填写表格时,请务必记录确切的时间和日期,以及网络条件(例如,在重大 NFT 铸造期间,延迟可能飙升)。还要记录客户端的物理位置和端点位置(如果已知)。这些背景信息对于解释数字至关重要。

为了更全面的比较,您还可以测试 WebSocket 连接并测量接收订阅通知的时间。这对于实时应用尤其重要。上面的脚本不涵盖 WebSocket,但您可以使用 ws 库扩展它。

  • 端点:您测试的 RPC URL。
  • 区域:您的位置或端点的位置。
  • 方法:测试的 JSON-RPC 方法。
  • 顺序延迟:5 个顺序请求的平均值。
  • 并发延迟:5 个并行请求的平均值。

常见故障与修复

在测量或使用 Base RPC 时,您可能会遇到超时、速率限制或不一致的结果。以下是常见问题及解决方法。

如果您收到 HTTP 429(请求过多),说明您遇到了速率限制。使用专用端点或降低请求频率。如果遇到超时,增加客户端超时时间或使用更近的端点。对于像 eth_getLogs 这样的重方法,按区块范围分页以避免超时。

另一个常见问题是收到 JSON-RPC 错误响应,代码为 -32005(超出限制)或 -32000(服务器错误)。这些通常表示请求过大或节点过载。对于 eth_getLogs,您可以减少区块范围或按地址过滤以限制结果集。对于 eth_call,您可以先使用 eth_estimateGas 确保调用有效。

不一致的结果也可能源于节点的同步状态。如果节点仍在同步,它可能返回过时数据或错误。检查 eth_syncing 方法以查看节点是否完全同步。如果返回 false,则节点已同步;否则,它仍在追赶。

最后,请注意“最新”、“安全”和“最终化”区块标签之间的区别。使用“最新”可能给您最新的区块,但它可能被重组。使用“安全”或“最终化”降低重组风险,但增加延迟。根据应用要求选择合适的标签。

  • 超时:增加客户端超时时间或使用延迟更低的专用端点。
  • 速率限制:使用专用端点或批处理请求以减少数量。
  • 重方法:按区块窗口分页 eth_getLogs(例如,每次请求 1000 个区块)。
  • 数据新鲜度:如果需要已结算数据,使用“安全”或“最终化”标签,但要注意延迟权衡。
  • 同步状态:检查 eth_syncing 以确保节点完全同步。

优化查询速度:最佳实践

为了减少有效延迟,请考虑以下优化。首先,使用 WebSocket(eth_subscribe)进行实时 newHeads 和日志,而不是轮询。这消除了轮询开销,并在数据可用时立即推送。其次,将多个 JSON-RPC 请求批处理到单个 HTTP 请求中,以减少往返次数。第三,缓存状态读取(例如,eth_call 结果)短 TTL,以避免重复调用。最后,按区块窗口分页 eth_getLogs,以避免重响应。

对于交易或索引应用,建议使用地理分布式或专用端点。公共端点方便但可能饱和。OnFinality 的 API 服务 提供具有可预测性能的专用端点,RPC 定价 透明。

当您需要多个独立调用时,批处理特别有效。例如,如果您需要获取 100 个地址的余额,您可以发送一个包含 100 个 eth_getBalance 调用的 JSON-RPC 批处理请求。这将 HTTP 往返次数从 100 减少到 1,大幅降低延迟。大多数 RPC 提供商支持批处理,但要注意响应大小限制。

缓存是另一个强大的技术。如果您频繁读取相同状态(例如,代币价格),您可以将结果缓存几秒。这对于可能昂贵的 eth_call 特别有用。使用短 TTL(例如,5-10 秒)以平衡新鲜度和性能。

对于 eth_getLogs,始终指定区块范围,如果可能,指定地址或主题过滤器。这减少了扫描的数据量和响应大小。如果您需要扫描大范围,将其分解为较小的窗口(例如,1000 个区块)并顺序或并行处理。这也有助于避免超时和速率限制。

最后,考虑使用负载均衡器或故障转移策略。如果您依赖单个 RPC 端点,您面临停机风险。使用多个端点并实施健康检查以自动切换到健康端点。这对于生产应用尤其重要。

  • 使用 WebSocket 订阅获取实时数据。
  • 批处理请求以减少往返次数。
  • 使用短 TTL 缓存状态读取。
  • 按区块窗口分页 eth_getLogs。
  • 为生产工作负载选择专用端点。
  • 使用多个端点和健康检查实施故障转移。

权衡与限制

测量延迟不是一次性任务;它应该是监控的一部分。然而,存在限制。像 comparenodes 这样的第三方基准提供独立排名,但使用自己的方法论,可能无法反映您的区域或工作负载。始终测量您自己的端点。

此外,延迟不是唯一指标。可靠性和速率限制也很重要。请参阅我们的指南 Base RPC 超时与重试Base RPC 速率限制与可靠性 了解更多。

另一个限制是延迟测量可能因网络抖动和服务器端缓存而失真。一些提供商缓存热门方法(如 eth_blockNumber)的响应,这可能使它们看起来比实际更快。为了获得真实情况,测试未缓存的方法,例如使用随机地址的 eth_getBalance。

最后,请记住延迟只是等式的一部分。吞吐量、错误率和数据新鲜度同样重要。返回过时数据的低延迟端点没有用。始终验证数据是最新且准确的。

  • 第三方基准可能无法反映您的区域或工作负载。
  • 延迟不是唯一指标;考虑可靠性和速率限制。
  • 缓存可能使测量失真;测试未缓存的方法。
  • 验证数据新鲜度和准确性。

后续步骤

既然您了解了 Base RPC 延迟,您可以将这些技术应用于您的应用。有关更多背景,请探索 Base 网络指南OnFinality Learn 中心。如果您需要专用端点,请查看 RPC Assistant 中的 Base RPC 端点设置

请记住定期测量您自己的延迟,并根据工作负载的变化调整策略。设置监控以跟踪延迟和错误率随时间的变化。使用本指南中提供的脚本作为起点,并根据您的具体需求进行自定义。

如需进一步阅读,请参阅官方 Base 文档 以获取有关 RPC 方法和网络参数的最新信息。OP-Stack 文档 也提供了对架构和性能特征的见解。

  • 定期测量延迟并监控趋势。
  • 为工作负载自定义测量脚本。
  • 查阅官方文档以获取更新。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始