Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
基础设施与运维阅读约 11 分钟

Chainstack 与 QuickNode:选择 RPC 提供商的可复现方法

以工作负载为先的框架,从计量方式、延迟、归档深度和故障转移等方面比较 Chainstack 与 QuickNode,并提供可在自有流量上重复运行的可执行探测脚本。

TL;DR

Chainstack 和 QuickNode 都是托管式多链 RPC 平台,因此决策很少取决于单一的头条数字。有意义的差异体现在:各自的请求计量方式、你的具体方法组合会产生多少成本、在你所在区域 p95 和 p99 延迟表现如何,以及归档、trace 和 WebSocket 工作负载是否包含在你的套餐中。本文提供一套可重复的流程:建模你的工作负载,用相同脚本探测两个端点,验证归档和调试行为,测试故障转移,最后再比较账单。请针对你自己的合约和区域亲自运行测量;在填入数据之前,下文中的数字均为占位符。

Chainstack 与 QuickNode 的决策究竟在检验什么

两家提供商都在大量 EVM 和非 EVM 网络上通过 HTTPS 和 WebSocket 提供 JSON-RPC,并且都提供共享节点和专用节点层级。这种重叠意味着功能清单比较通常以平局收场。更好的做法是把决策框定为工作负载适配问题:哪家提供商的计量模型、区域覆盖和套餐限制与你应用实际产生的流量相匹配?

本文是一套测量方法,而非结论。它假设你已经有候选网络、一组有代表性的 RPC 方法,以及至少一个可以将客户端指向两个端点的预发布环境。如果你只需要针对某条链的具体端点推荐,RPC Assistant 端点指南是更快的路径;当你需要向团队论证提供商选择时,再回到这里。

  • 范围:EVM JSON-RPC 加 WebSocket 订阅,并附带归档和 trace 方法的说明。
  • 不在范围内:协商的企业合同、法律条款以及提供商侧的事件历史。
  • 假设:你可以从部署所在的同一台机器和同一区域运行脚本。

前置条件与干净的测试环境

在比较任何内容之前,先固定变量。每个区域使用一台客户端机器、相同的 HTTP 库、相同的超时时间,并为两家提供商使用相同的请求负载。记录每个端点的套餐层级,因为免费套餐和付费套餐不可比较,会产生误导性的延迟和速率限制结果。

创建两个环境变量,每个提供商一个,绝不要在脚本中硬编码密钥。保留第三个变量用于备用端点,以便之后测试故障转移。将原始结果保存为 JSON,这样无需重新运行测试即可重新计算百分位数。

  • 固定客户端版本和操作系统,以免延迟差异来自库的差异。
  • 在一天中的同一时间、至少三个独立时间窗口运行每个探测。
  • 将 HTTP 状态码与延迟一起记录;快速的 429 不是快速的成功。
export CHAINSTACK_RPC_URL="https://your-chainstack-endpoint"
export QUICKNODE_RPC_URL="https://your-quicknode-endpoint"
export FALLBACK_RPC_URL="https://your-secondary-endpoint"
export TEST_ADDRESS="0x0000000000000000000000000000000000000000"

计量心智模型:credits、请求单元与方法权重

任何 RPC 比较中账单冲击的最大来源是方法权重。使用 credits 或请求单元计量的提供商通常会给不同的 JSON-RPC 方法分配不同权重:简单的区块号查询可能花费一个单位,而大范围的 eth_getLogs 或 debug_traceCall 可能花费很多。一个在头条配额上看起来更便宜的套餐,一旦套用你真实的方法组合,结果可能反转。

实用的方法是从你自己的日志构建方法组合表。对于你调用的每个方法,记录代表性时间段内的调用次数以及提供商公布的方法权重。相乘并求和,得到每周期加权单位数,然后将该数字与每个套餐包含的配额和超额费率进行比较。在运行任何延迟测试之前先做这件事,因为低流量下更便宜的端点在生产流量下可能是错误的选择。

文档记录的行为因套餐而异且可能变化,因此请将你读到的任何权重视为带日期的快照。每当应用调用模式发生变化时,尤其是添加索引、追踪或日志密集型分析时,都要重新核对权重。

  • 按方法统计调用次数,而不是总调用次数;平均值会掩盖昂贵的离群值。
  • 将读密集型方法(eth_call、eth_getLogs)与 trace 和 debug 方法分开。
  • 模拟 2 倍和 5 倍增长场景,观察超额费率何时开始占主导。

从自有流量构建工作负载画像

如果你已经在生产环境运行,从网关或客户端日志中导出一周的 RPC 方法调用计数。如果尚未上线,根据应用的读取路径估算:每个页面或任务调用余额、日志、收据和 trace 的频率。目标是得到一张可复用于两家提供商的小表格。

下面的脚本根据每个方法的权重映射,将方法计数的 JSON 文件汇总为加权总量。将权重映射替换为你正在评估的每个提供商套餐所公布的值,并将两个输出并排保留。

  • 用两家提供商的权重映射运行相同的计数。
  • 标记任何你无法从文档确认权重的方法。
  • 将原始计数文件纳入版本控制,以便比较可审计。
import json, sys

# method_counts.json: {"eth_call": 120000, "eth_getLogs": 4000, ...}
with open("method_counts.json") as f:
    counts = json.load(f)

# Replace with weights published for the plan you are evaluating.
weights = {
    "eth_call": 1,
    "eth_getLogs": 10,
    "eth_getBlockByNumber": 1,
    "debug_traceCall": 50,
}

total = 0
for method, n in counts.items():
    w = weights.get(method, 1)
    total += n * w
    print(f"{method:28s} calls={n:>10d} weight={w:>3d} units={n*w:>12d}")
print(f"TOTAL WEIGHTED UNITS: {total}")

可重复的延迟与可靠性探测

只有当请求负载、区域和并发度匹配时,延迟比较才有意义。先进行顺序探测以建立基线,然后增加并发以观察每个端点在负载下的表现。测量 p50、p95 和 p99 而非平均值,因为用户在拥塞时感受到的是尾部延迟。

下面的 Python 脚本对两个端点重复发出相同的 eth_blockNumber 调用,记录状态码和耗时,并打印百分位数。从用户所在的区域运行它,并针对更重的方法(如使用真实区块范围的 eth_getLogs)重复运行。

  • 每家提供商至少运行三个时间窗口,并比较分布而非单次运行。
  • 单独记录失败;突发期间的 429 是容量信号。
  • 如果用户地理分布广泛,从第二个区域重复测试。
import os, time, json, statistics, urllib.request

def probe(url, method="eth_blockNumber", params=None, n=200):
    payload = json.dumps({"jsonrpc":"2.0","id":1,"method":method,"params":params or []}).encode()
    results = []
    for _ in range(n):
        req = urllib.request.Request(url, data=payload, headers={"Content-Type":"application/json"})
        start = time.perf_counter()
        try:
            with urllib.request.urlopen(req, timeout=10) as r:
                r.read()
                status = r.status
        except Exception as e:
            status = getattr(e, "code", "error")
        results.append((status, (time.perf_counter() - start) * 1000))
    ok = [ms for s, ms in results if s == 200]
    ok.sort()
    def pct(p):
        return ok[min(len(ok)-1, int(len(ok)*p))] if ok else None
    return {"success": len(ok), "total": n, "p50": pct(0.50), "p95": pct(0.95), "p99": pct(0.99)}

for name in ["CHAINSTACK_RPC_URL", "QUICKNODE_RPC_URL"]:
    print(name, probe(os.environ[name]))

将结果记录到对比表中

将每次运行记录到表格中,使决策可审计且可复现。下表是模板;请填入你自己的测量值,而不是依赖任何已发布的基准。将套餐层级和测试日期保留在同一行,因为两者都会随时间变化。

提供商套餐层级区域方法成功 / 总数p50 (ms)p95 (ms)p99 (ms)备注
Chainstack(你的层级)(你的区域)eth_blockNumber(填写)(填写)(填写)(填写)(填写)
QuickNode(你的层级)(你的区域)eth_blockNumber(填写)(填写)(填写)(填写)(填写)
Chainstack(你的层级)(你的区域)eth_getLogs(填写)(填写)(填写)(填写)(填写)
QuickNode(你的层级)(你的区域)eth_getLogs(填写)(填写)(填写)(填写)(填写)

将成功率低于你阈值的任何行视为失败的候选,无论延迟如何。返回快速错误的提供商并不比稍后返回正确数据的提供商更快。

验证归档深度、trace 支持与 WebSocket 行为

归档和调试访问是最可能因套餐层级而异的功能,也是最容易用单次调用验证的功能。查询一个远在近期窗口之外的历史区块,确认响应包含状态而非修剪数据错误。然后尝试 trace 或 debug 方法,记录它是成功、返回不支持方法错误,还是被速率限制。

对于 WebSocket,订阅 new heads 并测量区块时间戳与客户端收到通知之间的间隔。故意断开并重新连接,观察每个端点如何处理重新订阅。如果你的应用依赖实时数据,这项测试比 HTTP 延迟更重要。

  • 历史区块上的修剪状态错误意味着该层级不包含归档访问。
  • debug_traceCall 上的不支持方法错误是能力缺口,而非延迟问题。
  • 对于 WebSocket,记录重连时间以及订阅是否自动恢复。
curl -s -X POST "$CHAINSTACK_RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["'"$TEST_ADDRESS"'","0x1"]}'

curl -s -X POST "$QUICKNODE_RPC_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"debug_traceCall","params":[{"to":"'"$TEST_ADDRESS"'","data":"0x"},"latest",{}]}'

突发下的故障转移与速率限制行为

生产可靠性更多取决于超出限制时会发生什么,而非稳态延迟。发送一个略高于预期峰值的短突发,观察响应:带 Retry-After 头的 429 是可恢复的,而静默超时或连接重置更难处理。然后通过将客户端指向主端点和备用端点并强制主端点失败,测试客户端的故障转移路径。

一个简单的模式是带健康检查的轮询或优先级端点列表。下面的配置展示了一个带超时和一次重试的优先级列表,你可以将其适配到你的客户端库。将备用端点放在不同的提供商上,这样单一提供商事件不会同时中断两条路径。

  • 记录每个请求由哪个提供商服务,以便归因事件。
  • 设置短于面向用户的 SLA 预算的超时时间。
  • 在真实突发期间测试故障转移,而不仅在稳态下。
const endpoints = [
  { name: "primary", url: process.env.CHAINSTACK_RPC_URL },
  { name: "secondary", url: process.env.QUICKNODE_RPC_URL },
  { name: "fallback", url: process.env.FALLBACK_RPC_URL },
];

async function rpc(method, params) {
  for (const ep of endpoints) {
    try {
      const res = await fetch(ep.url, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
        signal: AbortSignal.timeout(3000),
      });
      if (!res.ok) continue;
      const body = await res.json();
      if (body.error) continue;
      return { provider: ep.name, result: body.result };
    } catch (e) {
      // try next endpoint
    }
  }
  throw new Error("all endpoints failed");
}

将测量结果转化为成本与风险决策

一旦你有了加权单位、延迟百分位数、能力结果和故障转移行为,就将它们组合成决策矩阵。根据每个维度对你应用的重要程度进行加权:交易机器人可能高度重视 p99 延迟,而分析索引器可能重视日志查询成本和归档深度。将你的加权单位乘以每个套餐的超额费率,以估算当前和预计流量下的月度成本。

不要在未记录输入的情况下将决策压缩为单一分数。当提供商更改定价或你的方法组合变化时,你希望重新运行模型,而不是重做研究。对于要在多条链上统一到一个平台的团队,多链端点指南和网络目录有助于在承诺之前确认链覆盖范围。

  • 成本 = 包含配额成本 + (超出配额的加权单位 × 超额费率)。
  • 风险 = 事件暴露 × 故障转移质量 × 能力缺口。
  • 每季度或每当方法组合发生重大变化时重新运行模型。

排查常见的比较错误

大多数糟糕的提供商比较源于条件不匹配,而非真实的性能差异。下面的列表涵盖了团队对 RPC 端点进行基准测试时最常见的失败。

如果探测在一个提供商上返回错误而在另一个上不返回,在得出性能差距结论之前,先检查套餐层级和方法支持。如果延迟看起来低得难以置信,确认响应确实包含数据,而不是缓存或错误响应。如果 WebSocket 测试不稳定,验证你的客户端处理 ping/pong 和重新订阅,因为某些库在重连后会静默丢弃订阅。

  • 将免费套餐与付费套餐进行比较。
  • 从与生产环境不同网络的笔记本电脑上进行测试。
  • 比较头条配额时忽略方法权重。
  • 只测量平均值而错过尾部延迟。
  • 未经测试就假设包含归档或 trace 访问。
  • 故障转移到同一提供商的第二个端点。

局限性与后续步骤

此方法测量你能从自己的客户端观察到的东西:延迟、成功率、能力和建模成本。它无法捕捉提供商侧的事件历史、支持响应速度或合同条款,这些应单独评估。公布的权重和套餐限制会变化,因此任何比较都有保质期;请为结果标注日期并定期回顾。

一个实用的后续步骤是针对你的预发布工作负载运行探测脚本一周,填写对比表,并与拥有该应用的团队一起审查结果。如果你需要针对特定链的专用容量或可预测吞吐量,请结合你测量的单位查看专用节点选项和 RPC 定价结构。对于希望使用托管端点而不自行进行比较的团队,API 服务概览描述了端点的配置和扩展方式。

  • 至少运行一周的工作负载画像和延迟探测。
  • 用测量值和测试日期填写对比表。
  • 在签署合同前重新核对方法权重和套餐限制。
  • 无论哪家胜出,在生产环境中保留跨提供商的备用端点。

永远不用担心基础设施

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

开始