本文介绍如何测量和优化 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 的相关指南。