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

Sui 数据访问接口对比:JSON-RPC、gRPC 与 GraphQL

一份决策指南,对比 Sui 的三种数据访问接口——JSON-RPC、gRPC 与 GraphQL——涵盖类型化、数据新鲜度、工具链与一致性方面的权衡。

TL;DR

Sui 提供三种不同的数据访问接口:JSON-RPC,一种传统的方法导向接口;gRPC,一种类型化的 HTTP/2 + Protobuf 接口,被当前 SDK 使用;以及 GraphQL,一种由索引器支持的查询接口,具有关系视图和游标分页。它们并非同一事物的竞争品牌,而是在类型化、数据新鲜度、灵活性和工具链方面各有不同的权衡。JSON-RPC 通用性强但通信更频繁,且正被逐步弱化;gRPC 提供高效的类型化客户端和流式传输,但需要代码生成;GraphQL 允许客户端指定响应结构,并在一次往返中获取嵌套数据,但由于由索引器支持,可能落后于链尖。由于 GraphQL 由索引器支持,同一逻辑查询返回的数据所处的链位置可能与直接节点读取略有不同,因此不要在没有固定检查点的情况下,在同一个对一致性要求严格的流程中混用不同接口。本指南提供各接口的详细剖析、决策表、可运行的 Node.js 对比、可复现的结果表,以及选择适合你任务的接口的故障排除方法。

Sui 的三种数据访问接口概览

Sui 目前提供三种主要的数据访问接口,每种都有不同的设计中心。JSON-RPC 是传统的方法导向接口:你调用诸如 sui_getObject 或 sui_executeTransactionBlock 之类的命名方法,并接收 JSON 响应。gRPC 是较新的类型化 HTTP/2 + Protobuf 接口,被当前 SDK 使用;它在 .proto 文件中定义服务和消息,并生成客户端代码。GraphQL 是一种由索引器支持的查询接口,具有关系视图和游标分页,允许客户端在单次往返中精确请求所需的字段。

它们并非同一事物的竞争品牌。它们在类型化、数据新鲜度、灵活性和工具链方面各不相同。JSON-RPC 通用性强且无需 schema,但通信更频繁,并且正随时间被逐步弱化。gRPC 高效且支持流式传输,但需要代码生成和 HTTP/2。GraphQL 灵活且表达力强,但由索引器支持,因此可能落后于链尖。Sui API 参考文档将这些接口记录为不同的访问路径,而 gRPC 简介解释了支撑 gRPC 接口的类型化 HTTP/2 RPC 模型。

选择接口是一个关于权衡的决策,而不是某个接口普遍更好的问题。要更全面地了解 Sui 网络,请参阅 Sui 网络页面和 OnFinality Learn 中心。

  • JSON-RPC:方法导向、通用、无 schema、通信更频繁、正被逐步弱化。
  • gRPC:类型化 HTTP/2 + Protobuf、高效、支持流式传输、需要代码生成。
  • GraphQL:客户端指定结构、单次往返获取嵌套读取、由索引器支持因此可能落后于链尖。

JSON-RPC:传统的方法导向接口

Sui 上的 JSON-RPC 遵循 JSON-RPC 2.0 规范:你发送一个包含 jsonrpc、method、params 和 id 的请求对象,并接收包含 result 或 error 的响应。该接口是方法导向的——每个操作都是一个命名方法,例如 sui_getObject、sui_getTransactionBlock 或 sui_getLatestCheckpointSequenceNumber。由于在传输层是无 schema 的,你可以从任何 HTTP 客户端调用它,无需代码生成。

代价是通信更频繁。获取带有嵌套字段的对象可能需要多次调用:一次获取对象,另一次获取其动态字段,再一次获取创建它的交易。无法指定响应结构;你得到的是该方法固定的 JSON 结构。JSON-RPC 也正随时间被逐步弱化,因此新工作应优先使用可用的 gRPC 或 GraphQL。有关 JSON-RPC 接口的实用演练,请参阅 Sui RPC 指南(RPC Assistant)。

提供商对 JSON-RPC 的支持有文档记录,但因提供商和网络版本而异。一些提供商公开完整的方法集;其他提供商可能限制或弃用特定方法。请始终查看你的提供商的文档以获取当前方法列表。

  • 通用:可从任何 HTTP 客户端使用,无需代码生成。
  • 通信更频繁:嵌套读取可能需要多次往返。
  • 固定响应结构:无法由客户端指定字段选择。
  • 正被逐步弱化:新工作应优先使用 gRPC 或 GraphQL。

gRPC:类型化的 HTTP/2 + Protobuf 接口

gRPC 是当前 Sui SDK 使用的较新的类型化接口。它使用 HTTP/2 进行传输,使用 Protobuf 进行消息序列化,服务和消息在 .proto 文件中定义。gRPC 简介描述了该模型:客户端调用服务上的方法,生成的客户端处理序列化、帧封装和连接管理。这为你提供了编译时类型检查和高效的二进制负载。

gRPC 支持流式传输,这对账本和检查点服务很有用。对于高容量读取,它往往也比 JSON-RPC 更高效,因为 Protobuf 负载更小,且 HTTP/2 允许多路复用。代价是工具链:你需要从 .proto 文件生成客户端代码,并且你的运行时必须支持 HTTP/2。要深入了解,请参阅 Sui gRPC API 指南。

与 JSON-RPC 一样,gRPC 的可用性有文档记录,但因提供商和网络版本而异。一些提供商公开完整的服务集;其他提供商可能只公开子集。请查看你的提供商的文档以获取当前的服务和方法列表。

  • 类型化:通过生成的客户端进行编译时检查。
  • 高效:二进制 Protobuf 负载和 HTTP/2 多路复用。
  • 流式传输:支持账本和检查点数据的服务器端流式传输。
  • 工具链成本:需要代码生成和 HTTP/2 支持。

GraphQL:由索引器支持的查询接口

GraphQL 是一种由索引器支持的查询接口,具有关系视图和游标分页。与 JSON-RPC 和 gRPC 不同,GraphQL 允许客户端指定响应结构:你编写一个查询,精确命名你想要的字段,服务器只返回这些字段。这对嵌套读取尤其有用——在一次往返中获取一个对象及其动态字段、所有者和近期交易。GraphQL 学习页面解释了单端点查询模型、schema 和内省。

关键注意事项是数据新鲜度。由于 GraphQL 由索引器支持,它可能落后于链尖。索引器摄取检查点并构建关系视图;交易在链上最终确定与出现在索引中之间存在延迟。这意味着同一逻辑查询返回的数据所处的链位置可能与直接节点读取略有不同。要深入了解,请参阅 Sui GraphQL API 查询接口。

GraphQL 非常适合历史聚合、嵌套读取和客户端指定结构。它不太适合必须在精确链尖读取的对一致性要求严格的流程。提供商对 GraphQL 的支持有文档记录,但因提供商和网络版本而异。

  • 客户端指定结构:精确请求你需要的字段。
  • 嵌套读取:在一次往返中获取相关数据。
  • 由索引器支持:可能落后于链尖。
  • 游标分页:对大型结果集高效。

决策表:将常见任务映射到接口

下表将常见的 Sui 数据任务映射到最适合它们的接口。这是一个起点,而非硬性规则;你的提供商支持的接口以及你的一致性要求可能会改变选择。

对于发送或检查交易,gRPC 或 JSON-RPC 是自然的选择,因为它们直接与节点交互。对于获取带有嵌套字段的对象,GraphQL 通常更高效,因为它避免了多次往返。对于流式传输检查点,账本/流服务(通常通过 gRPC 流式传输公开)是正确的工具。对于历史聚合,GraphQL 或索引器通常最佳。

  • 发送/检查交易 → gRPC 或 JSON-RPC。
  • 获取带有嵌套字段的对象 → GraphQL。
  • 流式传输检查点 → 账本/流服务(gRPC 流式传输)。
  • 历史聚合 → GraphQL 或索引器。
  • 实时推送通知 → 订阅通道(WebSocket),而非这三种请求/响应接口中的任何一种。

跨接口的一致性注意事项

由于 GraphQL 由索引器支持,同一逻辑查询返回的数据所处的链位置可能与直接节点读取略有不同。如果你在一个对一致性要求严格的流程中混用接口——例如,通过 GraphQL 读取一个对象,然后通过 gRPC 提交交易——你可能会观察到落后于链尖的状态。这不是 bug;这是由索引器支持的接口的固有属性。

为避免不一致,请固定检查点。从直接节点接口(gRPC 或 JSON-RPC)读取最新的检查点序列号,然后将该检查点用作 GraphQL 查询的一致性边界。或者,将对一致性要求严格的流程保持在单一接口上。Sui 检查点流与账本服务提供了一种在检查点产生时观察它们的方法。

不要假设所有接口在同一挂钟时间处于相同的链位置。将数据新鲜度视为每个接口的属性,并据此设计你的应用程序。

  • GraphQL 可能落后于链尖,因为它由索引器支持。
  • 在对一致性要求严格的流程中混用接口时,固定检查点。
  • 尽可能将对一致性要求严格的流程保持在单一接口上。
  • 将数据新鲜度视为每个接口的属性。

可运行的 Node.js 对比:JSON-RPC vs GraphQL

以下 Node.js 脚本通过 JSON-RPC 调用和 GraphQL 查询运行同一个逻辑操作——获取同一个对象。它打印每种方式的往返次数和响应结构。请将端点 URL 和对象 ID 替换为你提供商的值。此示例使用现代 Node.js 中可用的内置 fetch API。

该脚本测量每次调用的挂钟时间并打印 JSON 响应。它并不断言哪个接口更快;它为你提供了一种可复现的方法,在你自己的端点上进行比较。针对你提供商的 JSON-RPC 和 GraphQL 端点运行它,并将结果记录在下一节的表格中。

// compare-jsonrpc-graphql.js
// Run with: node compare-jsonrpc-graphql.js

const JSONRPC_URL = 'https://your-provider.example/sui-jsonrpc';
const GRAPHQL_URL = 'https://your-provider.example/sui-graphql';
const OBJECT_ID = '0xYOUR_OBJECT_ID';

async function fetchJsonRpc() {
  const body = {
    jsonrpc: '2.0',
    id: 1,
    method: 'sui_getObject',
    params: [OBJECT_ID, { showType: true, showOwner: true, showContent: true }]
  };
  const start = Date.now();
  const res = await fetch(JSONRPC_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body)
  });
  const json = await res.json();
  const elapsed = Date.now() - start;
  console.log('JSON-RPC round-trips: 1');
  console.log('JSON-RPC elapsed ms:', elapsed);
  console.log('JSON-RPC response shape:', JSON.stringify(json).slice(0, 200));
  return json;
}

async function fetchGraphQL() {
  const query = `
    query GetObject($id: SuiAddress!) {
      object(address: $id) {
        address
        version
        digest
        asMoveObject {
          contents { type { repr } }
        }
      }
    }
  `;
  const start = Date.now();
  const res = await fetch(GRAPHQL_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, variables: { id: OBJECT_ID } })
  });
  const json = await res.json();
  const elapsed = Date.now() - start;
  console.log('GraphQL round-trips: 1');
  console.log('GraphQL elapsed ms:', elapsed);
  console.log('GraphQL response shape:', JSON.stringify(json).slice(0, 200));
  return json;
}

(async () => {
  await fetchJsonRpc();
  await fetchGraphQL();
})();

可运行的 Node.js 对比:gRPC 客户端(可选)

如果你的提供商公开 gRPC,并且你已从 .proto 文件生成了客户端,你可以扩展对比以包含 gRPC 接口。以下代码片段假设你有一个生成的客户端和一个正在运行的 gRPC 端点。它获取同一个对象并打印往返次数和响应结构。由于 gRPC 需要代码生成,此示例仅作说明;请根据你生成的客户端 API 进行调整。

目标不是宣布赢家,而是为你提供一种可复现的方法,在你自己的端点上测量往返次数、字节数、类型化和数据新鲜度。将你的观察记录在下一节的结果表中。

// compare-grpc.js (illustrative; requires generated client)
// Run with: node compare-grpc.js

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const PROTO_PATH = './sui.proto';
const GRPC_URL = 'your-provider.example:443';
const OBJECT_ID = '0xYOUR_OBJECT_ID';

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});
const suiProto = grpc.loadPackageDefinition(packageDefinition);

const client = new suiProto.sui.rpc.v2.LedgerService(
  GRPC_URL,
  grpc.credentials.createSsl()
);

const start = Date.now();
client.getObject({ objectId: OBJECT_ID }, (err, response) => {
  const elapsed = Date.now() - start;
  if (err) {
    console.error('gRPC error:', err.message);
    return;
  }
  console.log('gRPC round-trips: 1');
  console.log('gRPC elapsed ms:', elapsed);
  console.log('gRPC response shape:', JSON.stringify(response).slice(0, 200));
});

针对你自己端点的可复现结果表

使用下表记录你自己的测量结果。针对你提供商的端点运行上述脚本,并填写每一行。不要依赖已发布的基准数字;针对你实际使用的端点进行测量,因为延迟、吞吐量和数据新鲜度因提供商、区域和网络版本而异。

对于每个任务,记录所使用的接口、往返次数、近似响应字节数、响应是否类型化、相对于链尖的数据新鲜度以及任何备注。这为你提供了一份可复现的记录,你可以与团队分享,或在你的提供商更改其支持的接口时重新查看。

  • 任务:你执行的逻辑操作(例如,获取对象、发送交易)。
  • 使用的接口:JSON-RPC、gRPC 或 GraphQL。
  • 往返次数:所需的网络调用次数。
  • 字节数:近似响应大小。
  • 类型化?:响应是否经过类型检查(gRPC 是,JSON-RPC 否,GraphQL 为 schema 类型化)。
  • 相对于链尖的新鲜度:响应落后链尖多远。
  • 备注:任何提供商特定的注意事项或错误。

跨接口的局限性与权衡

接口可用性因提供商和网络版本而异。一些提供商公开全部三种接口;其他提供商只公开子集。JSON-RPC 正随时间被逐步淘汰,因此新工作应优先使用可用的 gRPC 或 GraphQL。GraphQL 可能落后于链尖,因为它由索引器支持。这三种接口都不能替代用于实时推送的订阅通道;为此,请使用 WebSocket 订阅接口,例如 Sui RPC WebSocket 订阅指南中描述的那种。

没有一种接口对所有任务都是最佳的。JSON-RPC 通用但通信更频繁且正被弱化。gRPC 类型化且高效,但需要代码生成和 HTTP/2。GraphQL 灵活且表达力强,但由索引器支持且可能过时。正确的选择取决于你的任务、你的一致性要求以及你的提供商支持的接口。

在评估提供商时,考虑他们公开的接口、其文档记录的数据新鲜度特征以及其定价模式。RPC 定价页面和 API 服务页面描述了 OnFinality 的产品;请始终与你的提供商核实当前的接口支持和限制。

  • 可用性因提供商和网络版本而异。
  • JSON-RPC 正被逐步淘汰;新工作优先使用 gRPC/GraphQL。
  • GraphQL 可能落后于链尖;为保持一致性请固定检查点。
  • 这三种接口都不能替代用于实时推送的订阅通道。

常见接口选择问题的故障排除

如果你从 GraphQL 看到过时数据,请检查你是否在链尖读取。GraphQL 由索引器支持,因此交易后立即查询可能不会反映它。固定一个检查点或等待索引器赶上。如果你需要链尖一致的读取,请使用 gRPC 或 JSON-RPC。

如果你的 gRPC 客户端连接失败,请验证你的运行时是否支持 HTTP/2,以及你是否从正确的 .proto 文件生成了客户端。一些提供商要求 TLS;其他提供商可能使用不同的端口。如果 JSON-RPC 方法返回错误,请检查该方法是否受你的提供商支持以及是否已被弃用。提供商特定的行为有文档记录但各不相同,因此请查阅你的提供商的文档。

如果你混用接口并看到不一致的结果,请将流程隔离到单一接口,或跨接口固定检查点。将你的观察记录在结果表中,以便复现和诊断问题。

  • GraphQL 数据过时:固定检查点,或使用 gRPC/JSON-RPC 进行链尖读取。
  • gRPC 连接失败:检查 HTTP/2 支持、代码生成、TLS 和端口。
  • JSON-RPC 错误:检查方法支持和弃用状态。
  • 混用接口流程不一致:隔离到单一接口或固定检查点。

在 Sui 上构建的后续步骤

首先确定你的提供商公开的接口。然后将你的任务映射到上面的决策表,并针对你的端点运行对比脚本。记录你的结果,并在你的提供商更改其支持的接口或 Sui 网络版本更新时重新查看它们。

要深入了解,请阅读 Sui gRPC API 指南、Sui GraphQL API 查询接口和 Sui 检查点流与账本服务指南。对于实时推送,请参阅 Sui RPC WebSocket 订阅指南。对于提供商特定的详细信息,请查阅 Sui RPC 指南(RPC Assistant)和 Sui 网络页面。

在构建过程中,请明确一致性要求。在混用接口时固定检查点,新工作优先使用 gRPC 或 GraphQL,并使用订阅通道进行实时推送。OnFinality Learn 中心收集了相关指南,API 服务页面描述了如何开始使用托管端点。

  • 确定你的提供商支持的接口。
  • 将任务映射到决策表,并使用脚本进行测量。
  • 新工作优先使用 gRPC 或 GraphQL;使用订阅进行推送。
  • 在对一致性要求严格的流程中混用接口时,固定检查点。

永远不用担心基础设施

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

开始