面向开发者的 Solana RPC:使用指南

Solana 开发者真正需要从 RPC 拿到什么。设置、常见模式、debug、把开发环境跟生产分开的架构选择。

BoltTx Team··12 min read
solanarpc开发者sdkweb3.jsanchor

如果你在 Solana 上做开发,RPC 是你接触的第一块基础设施,也是你最容易忽视、但又最关键的一块。很容易把它当成普通商品对待——Google 上随便挑一个,URL 一插,回头继续写业务逻辑。开发环境凑合够用,到了生产基本都会出问题。"我代码在 devnet 上 sendTransaction 成功了"和"我代码在 mainnet 真实负载下能稳定上链"——这两件事之间的差距,大部分都跟 RPC 选型有关。

这篇是给在 Solana 上做开发的工程师写的指南——RPC 到底做什么、怎么正确设置、有哪些常见模式和反模式、生产出问题时该往哪里查。

Solana RPC 是什么(代码层面)

机制上,Solana RPC 就是一个使用 JSON-RPC 协议的 HTTPS 端点。你的客户端(web3.js、Solana CLI、Anchor 框架、自己写的 Rust 代码)通过 HTTP 调用,RPC 节点要么返回链上状态、要么把交易转发给 validator。

你跟 RPC 打交道,主要做这几件事:

生产环境必须区分清楚:读流量和写流量的优化方向完全不同。读 RPC 强的服务商,写 RPC 不一定行;反过来也一样。

默认设置:Web3.js

大多数教程展示的最简单设置是这样的:

import { Connection, clusterApiUrl } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("mainnet-beta"));

开发环境凑合用没问题。生产环境完全不够用。clusterApiUrl("mainnet-beta") 返回的是 Solana 公共 RPC——有限流、没 SLA、网络拥堵时数据延迟严重。开发可以,生产绝对不行。

生产环境正确的写法:

import { Connection } from "@solana/web3.js";

const connection = new Connection(
  process.env.SOLANA_RPC_URL,  // 你 RPC 服务商的 URL
  {
    commitment: "confirmed",
    confirmTransactionInitialTimeout: 30_000,
    httpHeaders: {
      "Content-Type": "application/json",
    },
  }
);

URL 必须放环境变量。不要在代码里硬编码 RPC URL——后面想换服务商时会非常麻烦,dev/staging/prod 也会用不同的 URL。

读取数据:能跑得动的模式

常见的读操作和正确处理方式:

// 读单个账户
const account = await connection.getAccountInfo(publicKey);

// 批量读多个账户(一次往返)
const accounts = await connection.getMultipleAccountsInfo([key1, key2, key3]);

// 读 program 下的账户(带过滤条件)
const accounts = await connection.getProgramAccounts(programId, {
  filters: [
    { dataSize: 165 },  // SPL token account 大小
    { memcmp: { offset: 0, bytes: ownerKey } },
  ],
});

批量读用 getMultipleAccountsInfo 一次往返搞定,不要循环调用 getAccountInfo。循环调用是开发者浪费时间最常见的姿势之一——每次循环都是一次完整的网络往返。

getProgramAccounts 必须加过滤条件。 不加 filter 一次能拉几 MB 不相关数据。filter 是在 RPC 端执行的,比拉到客户端再过滤快得多。

变化慢的状态,能缓存就缓存。 代币 mint 元数据、program owner、ATA(Associated Token Account)地址这些数据并不是每个 slot 都在变。该缓存就缓存。

发送交易:能跑得动的模式

sendTransaction 我们另开了一篇详细写(Solana sendTransaction 最佳实践)。这里简短回顾一下:

const signature = await connection.sendTransaction(tx, signers, {
  skipPreflight: true,
  maxRetries: 0,
  preflightCommitment: "processed",
});

生产环境的几个关键点:

订阅推送:什么时候用

WebSocket 订阅是主动推送,不用你轮询。适合这几种场景:

const subId = connection.onAccountChange(
  publicKey,
  (accountInfo, context) => {
    console.log("Account changed at slot", context.slot);
  },
  "confirmed"
);

// 用完记得取消
connection.removeAccountChangeListener(subId);

代价是:订阅比轮询复杂得多,会遇到一堆轮询不会有的失败模式(重连逻辑、订阅泄漏管理)。轮询太慢或太贵的时候才用订阅,否则老老实实轮询

如果是大流量事件检测(多账户、多 program),标准 WebSocket 订阅模型不太够用,需要专门的流式数据源。这超出本篇范围,但你应该知道有这条路。

不同应用类型的常见模式

不同应用对 RPC 的用法差别很大:

钱包。 读为主(余额、交易历史、代币持仓)+ 偶尔写(用户主动 swap)。需要慷慨的读定价 + 可靠的交易发送。

索引器/分析平台。 大读取量、经常需要订阅推送,对写不敏感。读优化的 RPC 就行。

交易机器人。 重度 sendTransaction、对延迟极度敏感、有 MEV 风险。需要写优化 + 带 Anti-MEV 路由的 RPC。读流量适中。

dApp。 读写混合。面向终端用户,失败比机器人更明显。可靠性和可预测性比峰值性能更重要。

后端服务。 通常混合,看具体用例。

最普遍能跑得通的模式:读用一个 RPC(通常选读优化、定价合理的服务商),写用另一个(写优化、亚秒级落块、带 Anti-MEV 路由)。换个角度想:读 RPC 是数据库,写 RPC 是交易路由层。

常见反模式(按踩坑严重度排)

所有事情用同一个 RPC。 服务商各有强项——有些读得好但写一般,有些专长写但读贵。分开选

硬编码 URL。 永远用环境变量。后面一定会想换。

不处理限流。 生产 RPC 都会限流,客户端必须做指数退避重试,不要直接崩。

对慢数据高频轮询。 每秒查一次代币元数据是浪费。缓存

激进重连 WebSocket。 有些机器人每发一笔交易就重连一次。建立连接很贵,别这么干。

生产用 clusterApiUrl。 这是公共 RPC,开发可以,生产绝对不行。

不做监控。 大多数生产 bug 都是"我们不知道 X 在发生"。每笔签名级别的遥测就是解药。

不模拟就直接发。 真发交易前先 simulate 一下,绝大多数逻辑 bug 在花手续费前就能抓到。

把"交易已发送"当成"交易已上链"。 sendTransaction 返回签名不代表已经上链,永远要确认

这周可以做什么

如果你在开新 Solana 项目:

  1. 读 RPC 和写 RPC 分别选。优化目标完全不同。
  2. URL 放环境变量。不要硬编码。
  3. Connection 设合理默认值commitment: "confirmed"、合理的超时。
  4. 批量读用 getMultipleAccountsInfo,不要循环 getAccountInfo。一次往返搞定。
  5. getProgramAccounts 永远加过滤条件
  6. 早期就把每笔签名级别的遥测搭起来。后面一定用得上。
  7. 拿模拟负载压测。开发环境读得动不代表生产量级也读得动。

BoltTx 给开发者的能力

BoltTx 专门为 Solana 应用的写入场景设计:

集成方式:

import { Connection } from "@solana/web3.js";

const writeConnection = new Connection(
  "https://bolttx.io/?api-key=YOUR_API_KEY",
  "processed"
);

// 在你 sendTransaction 的地方用这个 connection
const signature = await writeConnection.sendTransaction(tx, signers, {
  skipPreflight: true,
  maxRetries: 0,
});

免费档注册。配一个读为主的 RPC,两边都能拿到最优。大多数生产团队跑的就是这种双 RPC 架构。

常见问题

生产里能直接用 Solana CLI 吗? ops 脚本可以。应用代码必须用 SDK(web3.js、anchor、solana-web3.rs)。

web3.js 和 Anchor 的区别? web3.js 是底层 Solana 交互 SDK;Anchor 是写 program、加上结构化账户校验的客户端框架。生产里这两个经常一起用。

能从 Python 用 Solana 吗? 能。solderssolana-py 是主要库。生态比 JS 那边不成熟,但够用。

读应该用哪个 commitment 级别? 大部分场景用 "confirmed"。要极致低延迟、能扛住 reorg 用 "processed""finalized" 留给"高价值且不可撤销"的决策。

开发要自己跑 RPC 节点吗? 开发不要——直接用托管服务商。生产到大规模时偶尔有团队会自建——但绝大多数团队最后都发现,托管 RPC 在成本和可靠性上都比自托管划算

延伸阅读

返回博客列表