RPC 客户端 - OpenZeppelin 文档

本文档介绍了 OpenZeppelin Monitor 中的 RPC 客户端实现,它具有自动端点轮换和回退功能,以确保可靠的区块链监控。重点介绍了 RPC 客户端的配置方法,包括 RPC URL 的配置,以及端点管理、轮换策略和重试策略。同时,还列出了 EVM 和 Stellar 网络中,监控器在每次 cron 迭代中发出的 RPC 调用列表,并提供了最佳实践和故障排除建议。

RPC 客户端

概述

OpenZeppelin Monitor 包括一个强大的 RPC 客户端实现,具有自动端点轮换和回退功能。即使单个 RPC 端点出现问题,这也能确保可靠的区块链监控。

  • 支持多个 RPC 端点,具有加权负载均衡

  • 端点故障时自动回退

  • 速率限制处理(429 响应)

  • 连接健康检查

  • 线程安全的端点轮换

配置

RPC URL

RPC 端点在网络配置文件中配置,并带有负载均衡权重:

{
  "rpc_urls": [\
    {\
      "type_": "rpc",\
      "url": {"type": "plain", "value": "https://primary-endpoint.example.com"},\
      "weight": 100\
    },\
    {\
      "type_": "rpc",\
      "url": {"type": "plain", "value": "https://backup-endpoint.example.com"},\
      "weight": 50\
    }\
  ]
}
对于高可用性设置,请配置至少 3 个具有适当权重的(私有)RPC 端点,以确保即使多个端点发生故障也能持续运行。

配置字段

字段 类型 描述
type_ String 端点类型(目前仅支持 “rpc”)
url.type String 密钥类型(“Plain”,“Environment” 或 “HashicorpCloudVault”)
url.value String RPC 端点 URL
weight Number 负载均衡权重(0-100)

端点管理

端点管理器处理

  • 基于权重的初始端点选择

  • 故障时自动轮换

  • 连接健康检查

  • 线程安全的端点更新

每个区块链网络类型都有其自己专门的传输客户端,该客户端包装了基本的 HttpTransportClient。 传输客户端的实现方式如下:

  1. 核心 HTTP 传输HttpTransportClient 提供核心 HTTP 功能,包括集成的可重试客户端。

  2. 特定于网络的传输

  • EVMTransportClient 用于 EVM 网络

  • StellarTransportClient 用于 Stellar 网络

轮换策略

RPC 客户端包含一个自动轮换策略,用于处理特定类型的故障:

  • 对于 429(请求过多)响应:

  • 立即轮换到备用 URL

  • 使用新端点重试请求

  • 继续此过程,直到成功或所有端点都已耗尽

配置选项

触发 RPC 端点轮换的错误代码可以在 src/services/blockchain/transports/mod.rs 文件中自定义。

pub const ROTATE_ON_ERROR_CODES: [u16; 1] = [429];

重试策略

传输层结合使用相同端点重试和端点轮换,以处理瞬时故障并保持服务可用性。

相同端点重试(通过 reqwest-retry

HttpTransportClient(以及扩展的 EVM 和 Stellar 客户端)使用 reqwest_middleware::ClientWithMiddleware。此客户端在初始化期间使用 utils::http::create_retryable_http_client 工具进行配置。此实用程序在共享的基础 reqwest::Client 之上分层 reqwest_retry::RetryTransientMiddleware

此中间件处理:

  • 当前活动的 RPC URL 发出的请求自动重试瞬时 HTTP 错误(例如,5xx 服务器错误、网络超时)。

  • 这些重试尝试之间的指数退避策略。

  • 诸如重试次数、退避持续时间和抖动之类的参数在 HttpRetryConfig 结构中定义(请参阅配置选项)。

  • 这种相同的端点重试机制是独立的,并且在端点轮换逻辑之抢跑。如果当前 URL 的所有相同端点重试失败,则该错误将由 EndpointManager 处理。

端点轮换(通过 EndpointManager

如果当前活动的 RPC URL 的所有相同端点重试都失败,或者如果收到某些 HTTP 状态代码(例如,429 请求过多,如 ROTATE_ON_ERROR_CODES 中所定义),则 EndpointManager(由 HttpTransportClient 使用)将尝试轮换到健康的备用 URL。这样可以确保如果一个端点变得持续不可用,系统可以切换到替代端点。备用 URL 的健康检查也受益于相同的端点重试机制。

配置选项

相同的端点重试行为通过 HttpRetryConfig 结构配置,该结构由 create_retryable_http_client 用于为 reqwest-retry 设置 ExponentialBackoff 策略。

HttpRetryConfig 的默认设置导致 ExponentialBackoff 策略大致等效于:

// 这说明了 HttpRetryConfig::default() 和
// create_retryable_http_client 创建的默认策略。
let http_retry_config = HttpRetryConfig::default();
let retry_policy = ExponentialBackoff::builder()
  .base(http_retry_config.base_for_backoff)
  .retry_bounds(http_retry_config.initial_backoff, http_retry_config.max_backoff)
  .jitter(http_retry_config.jitter)
  .build_with_max_retries(http_retry_config.max_retries);

可配置的选项在 HttpRetryConfig 结构中定义:

// 在 utils::http 中
pub struct HttpRetryConfig {
    /// 瞬时错误的最大重试次数(在初始尝试之后)。
    pub max_retries: u32,
    /// 第一次重试之前的初始退避持续时间。
    pub initial_backoff: Duration,
    /// 重试的最大退避持续时间。
    pub max_backoff: Duration,
    /// 指数退避计算的基数(例如,2)。
    pub base_for_backoff: u64,
    /// 要应用于退避持续时间的抖动。
    pub jitter: Jitter,
}

客户端架构确保了高效的资源使用和一致的重试行为:

  1. 单个基本 reqwest::ClientHttpTransportClient 创建,具有优化的连接池设置。此基本客户端是共享的。

  2. create_retryable_http_client 工具使用此基本客户端和一个 HttpRetryConfig 来生成一个 ClientWithMiddleware

  3. 然后,此 ClientWithMiddleware(“可重试客户端”)用于 HttpTransportClient 中的所有 HTTP 操作,包括初始健康检查、通过 EndpointManager 发送的请求以及轮换期间的 try_connect 调用。这样可以确保所有操作都受益于配置的重试策略和共享的连接池。

每个传输客户端都可以定义自己的重试策略:

// src/services/transports/http.rs
pub struct HttpTransportClient {
  pub client: ClientWithMiddleware,
  endpoint_manager: EndpointManager,
  test_connection_payload: Option<String>,
}

// 具有重试机制的客户端创建示例
// 使用默认重试策略
let http_retry_config = HttpRetryConfig::default();

// 创建基本 HTTP 客户端
let base_http_client = reqwest::ClientBuilder::new()
  .pool_idle_timeout(Duration::from_secs(90))
  .pool_max_idle_per_host(32)
  .timeout(Duration::from_secs(30))
  .connect_timeout(Duration::from_secs(20))
  .build()
  .context("Failed to create base HTTP client")?;

// 使用基本客户端和重试策略创建一个可重试的 HTTP 客户端
let retryable_client = create_retryable_http_client(
  &http_retry_config,
  base_http_client,
  Some(TransientErrorRetryStrategy), // 使用自定义或默认的重试策略
);

实现细节

EndpointManager 使用 HttpTransportClient 提供的启用重试的 ClientWithMiddleware 来尝试连接到主 URL。如果这些尝试(包括内部 reqwest-retry 重试)最终失败,并出现需要轮换的错误(例如,429 状态代码或持久性网络错误),则 EndpointManager 将启动 URL 轮换序列。

Fallback RPCPrimary RPCClientWithMiddleware (reqwest-retry)EndpointManagerHttpTransportClientUser/ApplicationFallback RPCPrimary RPCClientWithMiddleware (reqwest-retry)EndpointManagerHttpTransportClientUser/ApplicationRetryClient 在内部处理相同端点的重试(例如,对于 5xx)alt[备用健康检查成功][备用健康检查失败]alt[RPC_Primary 上的重试成功][RPC_Primary 上的所有重试失败(例如,网络错误或 429)]send_raw_request()send_raw_request(self, ...)POST to RPC_Primary成功成功成功响应最终错误(例如 429 或网络错误)来自 RPC_Primary 的最终错误决定轮换(基于错误类型)try_connect(Fallback_URL) (HTC 为此使用其 RetryClient)POST to RPC_Fallback (健康检查)成功 (健康检查)成功 (健康检查)成功 (健康检查)将活动 URL 更新为 RPC_FallbackPOST to RPC_Fallback (实际请求)成功成功成功响应Error (健康检查)Error (健康检查)Error (健康检查)最终错误(所有 URL 失败)错误响应

RPC 调用列表

以下是 monitor 为每种网络类型对 cron 计划的每次迭代进行的 RPC 调用列表。 随着正在处理的区块数量的增加,RPC 调用的数量也会增加,如果管理不当,可能会导致速率限制问题或成本增加。

Stellar 网络调用

EVM 网络调用

常见操作

net_version

eth_blockNumber

eth_getBlockByNumber

eth_getLogs

仅在需要时

eth_getTransactionReceipt

getNetwork

getLatestLedger

getLedgers

对于每个没有 ABI 的受监控合约

getLedgerEntries

getLedgerEntries

分批处理,每次 200 个

getTransactions

getEvents

网络初始化

分批处理,每次 200 个区块

处理区块

获取合约规范

获取 WASM 哈希

获取 WASM 代码

获取区块数据

获取交易

获取事件

完成

网络初始化

对于范围内的每个区块

处理区块

获取区块日志

获取交易回执

完成

处理新区块

EVM

  • RPC 客户端初始化(每个活动网络):net_version

  • 获取最新的区块号(每次 cron 迭代):eth_blockNumber

  • 获取区块数据(每个区块):eth_getBlockByNumber

  • 获取区块日志(每个区块):eth_getLogs

  • 获取交易回执(仅在需要时):

  • 当 monitor 条件需要特定于回执的字段(例如,gas_used)时

  • 监控交易状态且不存在用于验证状态的日志时

Stellar

  • RPC 客户端初始化(每个活动网络):getNetwork

  • 获取最新的账本(每次 cron 迭代):getLatestLedger

  • 获取账本数据(在单个请求中最多批处理 200 个):getLedgers

  • 在区块过滤期间,对于配置中没有 ABI 的每个受监控合约:

  • 获取合约实例数据:getLedgerEntries

  • 获取合约 WASM 代码:getLedgerEntries

  • 获取交易(在单个请求中最多批处理 200 个):getTransactions

  • 获取事件(在单个请求中最多批处理 200 个):getEvents

最佳实践

  • 配置多个具有适当权重的私有端点

  • 尽可能使用地理位置分散的端点

  • 监控端点健康状况并根据需要调整权重

  • 根据网络特性设置适当的重试策略

故障排除

常见问题

  • 429 请求过多:增加备用 URL 的数量、调整权重或降低监控频率

  • 连接超时:检查端点健康状况和网络连接

  • 无效响应:验证端点与你的网络类型是否兼容

日志记录

启用调试日志以获取详细的传输信息:

RUST_LOG=debug

这将显示:

  • 端点轮换

  • 连接尝试

  • 请求/响应详细信息

← 项目结构

自定义脚本 →

  • 原文链接: docs.openzeppelin.com/mo...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。