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

Polkadot RPC 延迟:Substrate 数据路径、测量与优化

了解 Polkadot RPC 延迟的驱动因素,如何可重复地测量,以及如何优化基于 Substrate 的 RPC 调用。

TL;DR

Polkadot RPC 延迟主要由 Substrate 的状态访问模式、网络地理位置和端点饱和决定。本指南解释了数据路径,提供了可重复的测量方法,并给出了优化策略。

什么决定了 Polkadot RPC 延迟?

Polkadot RPC 延迟是发送 JSON-RPC 请求到 Polkadot 节点和接收响应之间的时间。与 EVM 链上大多数调用命中简单的账户余额或存储槽不同,Polkadot 运行在 Substrate 上,这引入了不同的数据路径:状态存储在 Patricia Merkle 树中,许多 RPC 方法(如 state_getStorage)需要遍历该树。中继链还使用 GRANDPA 最终性,因此您查询的“最新”区块可能是软区块头,尚未最终确定。

主要因素包括:(1)客户端与节点之间的物理距离,(2)节点的存储类型(归档节点与修剪节点),(3)共享端点上的负载,以及(4)客户端库(例如 polkadot.js 与原始 JSON-RPC)的效率。本文解释了 Substrate 特有的机制,为您提供了可重复的测量方法,并列出了优化策略。

  • Substrate 状态 RPC 方法(state_getStoragestate_getPairsstate_queryStorage)比 EVM 链上的简单 eth_getBalance 更重。
  • GRANDPA 最终性意味着您可以查询尚未最终确定的区块;最终性滞后会影响一致性。
  • 归档节点保留所有历史状态,使深度查询更慢但可行;修剪节点仅提供近期状态。
  • WebSocket 连接有握手开销,重连风暴可能看起来像延迟峰值。

Substrate 数据路径:为什么 Polkadot RPC 不同

Polkadot 的中继链基于 Substrate 构建,所有状态都存储在树中。当您使用存储键调用 state_getStorage 时,节点必须从根到叶遍历树,从数据库读取节点。这比读取平面键值存储更耗费 I/O。树的深度随条目数量增长,因此对大型映射(如验证人集合)的查询可能更慢。

此外,Substrate 暴露了运行时 API 调用(例如 state_call 调用运行时方法),这些调用可能执行复杂逻辑。这些不是简单的读取;它们在 Wasm 环境中运行,可能需要更长时间。polkadot.js API 经常在底层使用这些,因此您可能会看到比原始 chain_getBlock 调用更高的延迟。

区块最终性:Polkadot 使用 GRANDPA 实现最终性,它落后于最佳区块。当您查询 chain_getHeader 而不指定区块哈希时,您会得到最佳区块,它可能未最终确定。如果您需要最终确定的状态,必须指定最终确定的区块哈希,这增加了查找步骤。这在 Polkadot JSON-RPC 文档Substrate RPC 文档 中有记录。

  • 状态树遍历增加了与树深度和数据库读取时间成比例的延迟。
  • 运行时 API 调用(state_call)比简单的存储读取更昂贵。
  • 最终性滞后:“最新”区块不一定最终确定;使用 finalized_head 保持一致性。
  • 归档节点存储所有历史状态,因此查询旧区块是可能的但更慢;修剪节点对旧状态返回错误。

测量 Polkadot RPC 延迟:可重复的方法

要准确测量延迟,您需要将网络往返时间与节点处理时间分开。以下方法使用 curl 进行 HTTP 测试,使用 Node.js 脚本进行 WebSocket 测试。它测量 system_chainchain_getBlockstate_getStorage 以及 WebSocket 连接/握手。从您自己的基础设施运行以获得与您位置相关的数字。结果由读者运行,而非供应商基准。

先决条件:curlwebsocat(或 Node.js 脚本)以及 Polkadot RPC 端点。您可以使用公共端点或自己的节点。为了可重复的结果,运行多次迭代并计算 p50/p95。

  • 使用 curl -w 捕获 HTTP 请求的计时细节。
  • 对于 WebSocket,使用带有 ws 包的 Node.js 脚本测量连接和请求延迟。
  • 至少运行 10 次迭代以获得有意义的百分位数。
  • 记录端点 URL、日期和您的地理位置以供参考。
#!/bin/bash
# HTTP 延迟测试 Polkadot RPC
ENDPOINT="https://rpc.polkadot.io"
for i in {1..10}; do
  curl -s -o /dev/null -w "%{time_total}\n" \
    -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","method":"system_chain","params":[],"id":1}' \
    $ENDPOINT
done
# 预期输出:10 个数字(秒),例如 0.234, 0.198, ...

WebSocket 延迟与重连影响

WebSocket 是 polkadot.js 的默认选择,因为它支持订阅。然而,WebSocket 连接有一个握手(HTTP 升级),这会在第一个请求上增加延迟。后续请求共享连接,因此每个请求的延迟较低。但如果连接断开,客户端会重新连接,重新公告(重新订阅所有活动订阅)可能导致请求突发,看起来像延迟峰值。

在测量 WebSocket 延迟时,将连接时间与请求时间分开。使用一个脚本连接一次,然后计时各个请求。另外,请注意 polkadot.js 可能批处理请求或使用订阅,这会影响感知延迟。

  • 握手为第一个请求增加约 1 个 RTT。
  • 重连触发重新订阅,可能导致临时负载。
  • 每次订阅后使用 unsub 避免过时订阅。
  • 对于一次性查询,HTTP 可能更简单、更快。
// Node.js WebSocket 延迟测试(需要 'ws' 包)
const WebSocket = require('ws');
const ws = new WebSocket('wss://rpc.polkadot.io');
let id = 0;
const t0 = Date.now();
ws.on('open', () => {
  console.log('连接时间 (ms):', Date.now() - t0);
  for (let i = 0; i < 10; i++) {
    const start = Date.now();
    ws.send(JSON.stringify({jsonrpc:'2.0', method:'system_chain', params:[], id:++id}));
    ws.on('message', (data) => {
      const msg = JSON.parse(data);
      if (msg.id === id) {
        console.log('请求', id, '延迟 (ms):', Date.now() - start);
      }
    });
  }
});
// 预期输出:连接时间和每个请求的延迟。

常见故障与修复

在测量或使用 Polkadot RPC 时,您可能会遇到超时、速率限制或过时数据。以下是常见问题及解决方法。

如果您在 state_getStorage 上对旧区块超时,您的节点可能已被修剪。使用归档端点或指定近期区块。如果您被限流,请降低请求频率或使用专用端点。如果您看到不一致的结果,请检查您是否查询了最终确定的区块。

  • 历史状态超时:使用归档节点或查询近期区块。
  • 速率限制:实现退避或使用专用端点(参见 Polkadot RPC 速率限制)。
  • WebSocket 断开:使用指数退避实现重连,并小心重新订阅。
  • 共享端点的高延迟:考虑地理分布式提供商或专用节点。
  • polkadot.js 订阅泄漏:使用后务必调用 unsub

优化策略

为了减少 Polkadot RPC 延迟,请关注以下方面:端点选择、客户端效率和查询设计。

端点选择:选择节点靠近您的用户或后端的提供商。像 OnFinality 的 API 服务 这样的地理分布式提供商将请求路由到最近的节点。避免公共端点,因为它们共享严重;在负载下它们可能有更高的延迟。

客户端:高效使用 polkadot.js。最小化订阅,每次使用后 unsub,并在可能的情况下批处理请求。对于一次性查询,使用原始 JSON-RPC over HTTP 以避免 WebSocket 开销。缓存不经常变化的状态。

查询设计:使用特定前缀缩小 state_getPairs 以减少数据传输。仅在必要时使用 state_queryStorage 进行历史查询。如果您需要完整区块,优先使用 chain_getBlock 而不是 chain_getBlockHash

  • 使用地理分布式端点或专用节点。
  • 保持 polkadot.js 订阅最少并始终取消订阅。
  • 在 SDK 允许的情况下批处理请求(例如 api.queryMulti)。
  • 缓存频繁访问的状态(例如运行时版本、常量)。
  • 缩小存储键前缀以减少响应大小。
  • 选择 WebSocket 用于订阅,HTTP 用于一次性调用。

权衡与限制

优化延迟通常涉及权衡。归档节点提供完整的历史数据,但更慢且更昂贵。修剪节点更快,但仅限于近期状态。使用专用端点减少争用,但成本更高。批处理请求减少往返,但可能增加批处理的响应时间。

测量本身有局限性:网络条件变化,您的结果取决于您的位置和端点的负载。始终记录您的方法并运行多次测试。像 CompareNodes 这样的独立基准测试提供他们自己的方法;将它们视为参考,而不是您自己的测量。

  • 归档与修剪:归档对于深层历史是必要的,但更慢。
  • 专用与共享:专用提供一致的延迟,但成本更高。
  • 批处理:减少开销,但可能延迟单个响应。
  • 测量差异:在不同时间和不同位置运行测试。

后续步骤

既然您了解了 Polkadot RPC 延迟,您可以将这些技术应用到自己的基础设施中。有关更多详细信息,请探索以下资源:

Polkadot 网络概述 开始了解架构。然后深入了解 Polkadot WebSocket RPC 指南 以了解连接最佳实践。如果您遇到限制,请阅读 Polkadot RPC 超时和重试Polkadot RPC 速率限制。对于端点选择,请参阅 Polkadot RPC 端点(RPC 助手) 并考虑 RPC 定价 以获取专用选项。最后,探索 OnFinality Learn 中心 获取更多指南。

永远不用担心基础设施

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

开始