Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
RPC 故障排查12 分钟阅读

Monad RPC 延迟:测量、瓶颈与查询速度优化

了解如何测量 Monad RPC 延迟,理解 Monad 并行执行和亚秒级区块特有的瓶颈,并优化查询速度。

TL;DR

本文介绍如何测量和优化 Monad RPC 延迟。涵盖 Monad 的独特架构(并行执行、延迟执行、亚秒级区块)及其对 RPC 行为的影响。您将获得使用 curl 和 viem 的可复现测量方法,以及批处理、缓存和 WebSocket 订阅等优化策略。

直接回答:什么决定了 Monad RPC 延迟?

Monad RPC 延迟是发送 JSON-RPC 请求到接收响应之间的时间。它主要由三个因素决定:到端点的网络距离、端点的负载(尤其是共享公共端点)以及特定 RPC 方法的权重。在 Monad 上,亚秒级区块时间和延迟执行模型增加了一个独特的复杂性:区块头的新鲜度和状态可用性可能因节点处理交易的方式而异。要获得低延迟,您需要一个地理位置接近的专用端点,并且必须设计轻量且可缓存的查询。

本文是测量和优化 Monad RPC 延迟的实用指南。它不是供应商基准测试;您在结果表中看到的所有数字都旨在由您在自己的环境中复现。我们将涵盖 Monad 的架构、分步测量方法、常见瓶颈和优化技术。

  • 网络距离:客户端与 RPC 端点之间的物理距离会增加往返时间(RTT)。
  • 端点饱和:公共端点是共享的;其他人的大量使用可能导致排队和速率限制。
  • 方法权重:在大区块范围内使用 eth_getLogs 比 eth_chainId 重得多。
  • Monad 的延迟执行:区块快速提出,但状态可能不会立即可用,直到执行赶上。
  • WebSocket 与轮询:在快速链上,每 400 毫秒轮询一次 eth_blockNumber 可能会错过区块;订阅更高效。

Monad 的架构及其对 RPC 的影响

Monad 是一个兼容 EVM 的第 1 层区块链,使用并行乐观执行和延迟执行来实现高吞吐量(设计目标为 10,000 TPS)和亚秒级区块时间(约 1 秒或更短)。MonadBFT 共识实现了快速最终性。对于 RPC 客户端,这意味着新区块频繁到达,并且状态可能在所有交易完全执行之前被乐观更新。

Monad 文档 解释说,虽然区块快速生成,但交易的执行可以延迟。这意味着当您查询 eth_blockNumber 时,您可能会获得最新的区块头,但如果执行尚未完成,该区块上的 eth_getBalance 或 eth_call 可能无法反映所有交易。这是文档化的行为,而不是错误。对于大多数用例,延迟很小,但对于对延迟敏感的应用程序,您应该注意这一点。

亚秒级区块的另一个后果是,每 1 秒轮询一次新区块可能会错过区块。WebSocket 订阅(eth_subscribe)是获取实时 newHeads 和日志的推荐方式。Monad 的文档还指出,如果您查询广泛的区块范围,eth_getLogs 可能会很昂贵,因此您应该按区块窗口进行分页。

  • Monad 的并行执行允许多个交易同时处理,但 RPC 状态读取可能会看到一致的快照。
  • 延迟执行意味着区块提出后,其状态可能不会立即可用。
  • 亚秒级区块时间使轮询效率低下;使用 WebSocket 订阅获取实时数据。
  • eth_getLogs 是一个重方法;始终限制区块范围并使用分页。

可复现的测量方法

要准确测量 Monad RPC 延迟,您需要将网络延迟与服务器处理时间分开。以下方法使用 curl 进行快速检查,并使用带有 viem 的 Node.js 脚本进行更详细的统计。所有测量都应由您运行;我们提供代码和结果表供您填写。

假设:您已安装 Node.js 18+,并且可以访问 Monad RPC 端点(公共或专用)。测试日期为 2026-09-02。我们建议从地理位置接近目标端点的机器上运行测试,以尽量减少网络噪声。每次测试运行多次(例如 10 次迭代),并计算中位数(p50)和第 95 百分位(p95)。

  • 使用 curl -w 测量总时间和细分(DNS、连接、TTFB、总时间)。
  • 使用 viem 脚本发送顺序和并发请求以测量 p50/p95。
  • 在下面的表格中记录您的结果;不要与供应商基准进行比较。
curl -s -o /dev/null -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  -X POST https://rpc.monad.xyz -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'

# 预期输出形状(值会有所不同):
# DNS: 0.001s
# Connect: 0.020s
# TTFB: 0.050s
# Total: 0.051s

使用 viem 的 Node.js 测量脚本

以下脚本使用 viem 发送一系列 JSON-RPC 请求并测量延迟。它测试 eth_chainId(廉价)、eth_blockNumber(廉价)、eth_getBalance(中等)和 eth_getBlockByNumber(中等)。它顺序和并发运行每个方法以模拟真实负载。脚本输出 p50 和 p95 延迟(毫秒)。

要运行它,请将代码保存为 measure-monad-latency.mjs 并使用 node measure-monad-latency.mjs 运行。您需要先安装 viem:npm install viem

import { createPublicClient, http } from 'viem';

const RPC_URL = process.env.RPC_URL || 'https://rpc.monad.xyz';
const client = createPublicClient({ transport: http(RPC_URL) });

const methods = {
  eth_chainId: () => client.getChainId(),
  eth_blockNumber: () => client.getBlockNumber(),
  eth_getBalance: () => client.getBalance({ address: '0x0000000000000000000000000000000000000000' }),
  eth_getBlockByNumber: () => client.getBlock({ blockNumber: 1n }),
};

async function measure(method, iterations = 10) {
  const times = [];
  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    await method();
    times.push(performance.now() - start);
  }
  times.sort((a, b) => a - b);
  const p50 = times[Math.floor(iterations * 0.5)];
  const p95 = times[Math.floor(iterations * 0.95)];
  return { p50, p95 };
}

async function measureConcurrent(method, iterations = 10) {
  const times = [];
  const start = performance.now();
  await Promise.all(Array.from({ length: iterations }, () => method()));
  times.push(performance.now() - start);
  return { p50: times[0], p95: times[0] }; // 简化的并发测量
}

console.log('顺序测量(毫秒):');
for (const [name, fn] of Object.entries(methods)) {
  const { p50, p95 } = await measure(fn);
  console.log(`${name}: p50=${p50.toFixed(2)} p95=${p95.toFixed(2)}`);
}

console.log('\n并发测量(10 个并行请求,总时间毫秒):');
for (const [name, fn] of Object.entries(methods)) {
  const { p50 } = await measureConcurrent(fn);
  console.log(`${name}: total=${p50.toFixed(2)}`);
}

// 预期输出形状(值会有所不同):
// 顺序测量(毫秒):
// eth_chainId: p50=12.34 p95=15.67
// eth_blockNumber: p50=13.45 p95=16.78
// eth_getBalance: p50=20.11 p95=25.34
// eth_getBlockByNumber: p50=18.22 p95=22.45
//
// 并发测量(10 个并行请求,总时间毫秒):
// eth_chainId: total=45.67
// eth_blockNumber: total=48.90
// eth_getBalance: total=70.12
// eth_getBlockByNumber: total=65.43

结果表(读者运行测量)

在下面的表格中填写您自己的测量结果。这不是供应商基准测试;它是一种让您比较端点或跟踪性能随时间变化的方法。使用相同的 RPC URL 并多次运行脚本以获得稳定的结果。

比较端点时,请确保从同一台机器并在一天中的相似时间运行测试以减少差异。

  • 记录端点 URL、测试日期和时间。
  • 至少运行脚本 3 次,并取 p50 值的中位数。
  • 注意您遇到的任何速率限制(HTTP 429)或超时。
| 方法 | p50 (ms) | p95 (ms) | 并发总时间 (ms) |
|--------|----------|----------|------------------------|
| eth_chainId | | | |
| eth_blockNumber | | | |
| eth_getBalance | | | |
| eth_getBlockByNumber | | | |

(示例行:eth_chainId | 12.3 | 15.6 | 45.7)

常见瓶颈及解决方法

即使使用快速端点,您也可能会遇到延迟瓶颈。最常见的是:使用距离较远的公共端点、发出过多请求(尤其是重请求)以及轮询新区块而不是订阅。以下是具体修复方法。

首先,选择地理位置接近您应用程序的端点。如果您的用户是全球性的,请使用地理分布式提供商或专用端点。OnFinality 的 API 服务 提供具有全球覆盖的专用端点,但您应根据自己的测试进行评估。

其次,批量处理您的 JSON-RPC 请求。不要发送 10 个单独的 eth_getBalance 调用,而是使用批量端点在一个 HTTP 请求中发送它们。这减少了往返和开销。许多提供商支持批处理;请查看您的提供商的文档。

第三,缓存只读状态。如果您经常查询相同的账户余额或合约状态,请在客户端缓存它,并在新区块时使其失效。这减少了 RPC 负载和延迟。

第四,使用 eth_getLogs 时,始终指定区块范围并进行分页。例如,以 1000 个区块为块查询日志。这防止节点扫描整个链。

最后,对于实时数据,使用 WebSocket 订阅(eth_subscribe)而不是轮询。Monad 的亚秒级区块意味着每 1 秒轮询一次将错过区块。有关详细信息,请参阅我们的 Monad WebSocket RPC 指南

  • 地理距离:使用地理分布式或专用端点。
  • 批处理:将多个请求合并到一个 HTTP 调用中。
  • 缓存:在客户端缓存余额和状态读取。
  • eth_getLogs 分页:限制区块范围并使用分页。
  • WebSocket 订阅:用于 newHeads 和日志,而不是轮询。

Monad 特定注意事项:延迟执行和区块新鲜度

Monad 的延迟执行可能导致 eth_blockNumber 返回尚未完全执行的区块。这是文档化的行为:区块头立即可用,但状态读取(eth_getBalance、eth_call)可能反映该区块中某些交易应用之前的状态。对于大多数应用程序,这不是问题,因为延迟只有几毫秒。但是,如果您需要读取依赖于最新交易的状态,则应等待区块最终确定或使用确保执行的方法。

Monad 的文档建议使用带有 'pending' 标签的 eth_getBlockByNumber 来获取最新状态,但这并不总是可靠的。最安全的方法是使用配置为等待执行的专用端点,或者在看到新区块后添加一个小延迟(例如 100 毫秒)再查询状态。

另一个考虑因素是区块时间。使用亚秒级区块,eth_blockNumber 方法将非常频繁地返回新值。如果您正在轮询,您可能会被速率限制。使用 WebSocket 订阅来接收 newHeads 事件,这更高效且延迟更低。

  • 延迟执行:eth_blockNumber 可能返回状态尚未完全更新的区块。
  • 要在新区块后读取状态,请等待执行赶上或使用专用端点。
  • 亚秒级区块使轮询效率低下;使用订阅。

权衡与限制

优化延迟通常涉及权衡。例如,使用专用端点比公共端点成本更高,但提供一致的性能。批处理请求减少了延迟,但增加了代码的复杂性。缓存状态减少了 RPC 负载,但如果未正确失效,可能会提供过时的数据。

还有一些限制是您无法优化的。网络延迟受光速限制;您无法将其减少到物理距离之外。公共端点是共享的,因此您无法控制其他用户的负载。Monad 的延迟执行是协议功能;您无法禁用它。

测量延迟时,请注意您的结果将根据端点、一天中的时间和网络条件而变化。始终运行多次测试并使用百分位数(p50、p95)而不是平均值来获得真实的图景。

  • 专用端点成本更高,但提供一致的性能。
  • 批处理增加了代码复杂性,但减少了往返。
  • 如果未在新区块上失效,缓存可能会提供过时的数据。
  • 网络延迟是物理性的;您无法将其减少到距离之外。
  • 公共端点是共享的;您无法控制其他用户的负载。

后续步骤和进一步阅读

既然您知道如何测量和优化 Monad RPC 延迟,您可以将这些技术应用于您自己的应用程序。首先针对您当前的端点运行测量脚本,然后尝试优化并再次测量。您应该会看到 p95 延迟的改进。

有关更多 Monad RPC 指南,请查看我们的其他文章:Monad RPC 端点(RPC 助手) 用于端点选择,Monad RPC 超时和重试 用于处理超时,以及 Monad RPC 速率限制和 429 用于避免速率限制。另请参阅 Monad WebSocket RPC 指南 获取实时数据。

如果您正在 Monad 上构建,您可能还想探索 Monad 主网网络页面 了解网络详细信息,以及 OnFinality Learn 中心 获取更多教程。有关专用端点的定价,请参阅 RPC 定价

  • 针对您的端点运行测量脚本并记录结果。
  • 实施批处理、缓存和 WebSocket 订阅。
  • 重新测量以查看改进。
  • 探索有关超时、速率限制和 WebSocket 的相关指南。

永远不用担心基础设施

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

开始