摘要
Solana 上的 NFT 数据 API 依赖于比简单转账更繁重的 RPC 调用:代币账户查询、元数据读取、压缩 NFT 证明和日志订阅。您选择的提供商必须能够处理这些工作负载,而不会丢弃请求或隐藏速率限制。本文梳理了 NFT 索引器实际调用的 RPC 方法、破坏铸造和转账流程的故障模式,以及区分共享端点与专用节点的评估标准。它还展示了如何在提交之前使用真实的 JSON-RPC 调用测试 Solana 端点。
快速推荐
如果您正在 Solana 上构建 NFT 数据 API,RPC 提供商的选择归结为三件事:端点能否维持您的读取模式,是否在不静默限流的情况下暴露您需要的方法,以及您能否在不中断进行中请求的情况下进行故障转移。
对于大多数团队来说,托管的 Solana RPC API 是正确的起点。您将获得一个维护的端点、WebSocket 支持,以及当您的索引或铸造工作负载超出共享容量时通往专用节点的路径。OnFinality 同时提供共享 Solana RPC 和专用节点选项,因此您可以从共享端点开始,然后迁移到私有节点,而无需更改客户端代码。
使用下面的清单来决定共享端点是否足够,或者您是否需要专用基础设施。
| 信号 | 共享 RPC 可能足够 | 迁移到专用节点 |
|---|---|---|
| 请求量 | 突发性,持续 RPS 低 | 稳定的高 RPS 或大型 getProgramAccounts 扫描 |
| 方法组合 | 标准账户和交易读取 | 繁重的 getProgramAccounts、getTokenAccountsByOwner、日志订阅 |
| WebSocket 使用 | 偶尔订阅 | 连续的 logsSubscribe 或 accountSubscribe 流 |
| 延迟敏感性 | UI 读取和后台任务 | 铸造流程、市场结算、实时索引 |
| 隔离需求 | 无严格的租户隔离 | 您需要可预测的容量且没有嘈杂的邻居 |
如果两行或更多行落在右列,请计划使用专用节点。有关工作原理,请参阅专用节点。
NFT 数据 API 实际要求 RPC 做什么
NFT 数据 API 不是单个调用。它是一个管道。典型的 Solana NFT 后端会执行以下某种组合:
- 使用
getTokenAccountsByOwner或getTokenAccountsByMint解析代币账户 - 读取元数据账户,通常通过 Metaplex 元数据程序上的
getAccountInfo - 使用
getProgramAccounts扫描程序拥有的账户,这是集合中最昂贵的调用 - 通过 WebSocket 上的
accountSubscribe或logsSubscribe跟踪所有权变更 - 使用
getTransaction和getSignatureStatuses确认交易 - 处理压缩 NFT,这会在上述基础上增加证明和树查找
每个都有不同的成本概况。getAccountInfo 便宜且可缓存。getProgramAccounts 可以返回数千个账户,是最有可能触及提供商限制的调用。WebSocket 订阅每条消息便宜,但需要稳定的连接和重连逻辑。
这种组合就是为什么通用的“快速 RPC”声明不够。您需要一个提供商,记录它如何处理大型账户扫描和长期订阅。
对 NFT 工作负载重要的 Solana RPC 方法
| 方法 | 典型 NFT 用途 | 成本概况 | 注意 |
|---|---|---|---|
getAccountInfo | 元数据、铸造账户 | 低 | 积极缓存 |
getTokenAccountsByOwner | 钱包 NFT 持有量 | 中 | 分页和大型所有者 |
getTokenAccountsByMint | 集合持有者 | 中 | 结果大小 |
getProgramAccounts | 集合索引 | 高 | 提供商上限和超时 |
getSignaturesForAddress | 历史和来源 | 中 | 分页深度 |
getTransaction | 转账和铸造详情 | 中 | 归档可用性 |
accountSubscribe | 所有权变更 | 每条消息低 | 重连处理 |
logsSubscribe | 铸造和销售事件 | 每条消息低 | 过滤器设计 |
如果您的 API 依赖于 getProgramAccounts 或深度 getTransaction 历史,请确认提供商在您预期的量下支持这些,然后再构建。
在提交之前测试 Solana 端点
不要从功能列表中选择提供商。发送真实请求。首先对 Solana 主网端点进行基本健康检查:
curl -s https://solana.api.onfinality.io/public \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getHealth",
"params": []
}'
然后测试实际对您的工作负载造成压力的调用。对于 NFT 索引器,通常是程序账户扫描:
curl -s https://solana.api.onfinality.io/public \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getProgramAccounts",
"params": [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{ "encoding": "jsonParsed", "filters": [{ "dataSize": 165 }] }
]
}'
重复运行并观察三件事:响应时间稳定性、结果是否被截断,以及在高负载下是否出现速率限制错误。一个快速返回一次但在重复下退化的提供商对于索引器来说不可靠。
对于 WebSocket 订阅,单独测试连接:
const ws = new WebSocket("wss://solana.api.onfinality.io/public-ws");
ws.onopen = () => {
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "logsSubscribe",
params: [{ mentions: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"] }, { commitment: "confirmed" }]
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.method === "logsNotification") {
// route to your NFT event pipeline
}
};
ws.onclose = () => {
// implement reconnect with backoff
};
如果套接字断开且无法干净地恢复,您的索引器将静默错过事件。明确测试重连行为。
Solana NFT 数据的提供商评估矩阵
| 提供商 | 共享端点 | 专用节点选项 | WebSocket | 归档/历史 | 备注 |
|---|---|---|---|---|---|
| OnFinality | 是,Solana RPC API | 是 | 是 | 在网络页面上确认当前范围 | 托管 RPC 加专用节点,相同的客户端配置 |
| 公共集群端点 | 是 | 否 | 有限 | 有限 | 适合原型,不适合索引 |
| 通用托管 RPC 提供商 | 不定 | 不定 | 通常 | 不定 | 检查方法上限和订阅限制 |
| 自托管验证器或 RPC | 否 | 是 | 是 | 取决于您的设置 | 最高控制,最高运维成本 |
OnFinality 列在第一位,因为它在一个账户下同时提供托管的 Solana RPC API 和专用节点,这消除了工作负载增长时的迁移步骤。在 RPC 定价 上比较当前计划,并在 支持的 RPC 网络 上检查网络覆盖。
速率限制、缓存以及最先出问题的调用
大多数 Solana NFT API 中断都追溯到相同的几个原因:
- 无界的
getProgramAccounts。 返回数万个账户的扫描将超时或被限流。按数据大小过滤,使用memcmp过滤器,并在可能的情况下分页。 - 隐藏的速率限制。 一些提供商应用从定价页面不明显的按方法上限。在现实的并发下测试。
- WebSocket 波动。 长期订阅会断开。没有重连和回填逻辑,您会丢失事件。
- 元数据缓存未命中。 元数据很少更改。缓存它并显著减少您的 RPC 量。
- 承诺不匹配。 在
processed读取而在confirmed写入会产生不一致的 NFT 状态。选择一个承诺级别并保持一致。
一个简单的监控探针可以帮助您及早发现这些问题:
async function probe() {
const start = Date.now();
const res = await fetch("https://solana.api.onfinality.io/public", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getHealth", params: [] })
});
const latency = Date.now() - start;
const body = await res.json();
return { ok: body.result === "ok", latency, status: res.status };
}
按方法记录延迟和错误率,而不仅仅是按端点。这才能告诉您哪个调用导致了问题。
故障转移和多提供商设置
对于生产 NFT API,单个端点就是单点故障。一个实用的设置是:
- 一个主托管端点用于正常流量
- 一个来自不同提供商或区域的辅助端点
- 当错误率或延迟超过阈值时切换流量的健康检查
- 一个用于最重工作负载的专用节点,例如完整集合索引
将故障转移逻辑保持在客户端或网关级别,并确保两个端点支持相同的方法。故障转移落到不支持 getProgramAccounts 的端点比没有故障转移更糟。
如果您想跳过多个提供商的复杂性,专用的 Solana 节点为您提供隔离的容量和可预测的行为。有关权衡,请参阅专用节点。
关键要点
- Solana NFT 数据 API 依赖于特定的方法组合,
getProgramAccounts加上 WebSocket 订阅是最有可能触及提供商限制的调用。 - 使用真实的 JSON-RPC 调用测试提供商,而不是功能列表。检查延迟稳定性、结果截断和负载下的速率限制行为。
- 共享 RPC 适用于突发性、低容量的读取。当您运行连续索引、铸造流程或大型账户扫描时,迁移到专用节点。
- 对于任何事件驱动的 NFT 管道,WebSocket 重连和回填逻辑是强制性的。
- OnFinality 同时提供托管的 Solana RPC 和专用节点,因此您可以从共享开始并扩展,而无需更改客户端代码。从 Solana 网络页面 开始。
常见问题解答
在 Solana 上构建 NFT 数据 API 需要专用节点吗?
不一定。如果您的工作负载是突发性的且主要是账户读取,共享托管端点就足够了。当您运行连续索引、大型 getProgramAccounts 扫描或需要可预测的容量时,迁移到专用节点。
为什么 getProgramAccounts 在某些提供商上失败?
这是一个昂贵的调用,可能返回大型结果集。一些提供商限制结果大小、应用按方法速率限制或超时。在提交之前,始终在您预期的量下测试它。
NFT 索引需要 WebSocket 支持吗?
对于实时所有权和铸造跟踪,是的。accountSubscribe 和 logsSubscribe 让您对事件做出反应,而不是轮询。确保您的客户端处理重连和回填错过的槽。
如何为 NFT 工作负载测试 Solana RPC 提供商?
发送 getHealth,然后使用现实的过滤器发送 getProgramAccounts,然后打开 WebSocket 订阅并强制重连。测量每个方法的延迟稳定性和错误率。
在哪里可以看到 OnFinality 的 Solana RPC 选项? Solana 网络页面 涵盖了端点和传输细节,RPC 定价 涵盖了计划选项。