迁移到另一家 Solana RPC 服务商

为什么换端点只要一行、而迁移不止一行,切换之前该测什么,以及那些只在高负载下才显现的差异。

BoltTx Team··14 min read
solanarpc迁移基准测试基础设施交易上链

换 Solana RPC 服务商就是换一个 URL。代码上确实只要这么多 —— 而这正是大多数迁移做得不好的原因。

★换是简单的。知道它有没有帮上忙,才是真正的工作。★

确实只要一行的那部分

const connection = new Connection(NEW_ENDPOINT, "confirmed");

Solana 的 JSON-RPC 接口是标准化的,所以同一份客户端代码对任何合规端点都能用。没有 SDK 要换,也没有数据要迁。

★而这也正是陷阱。★ 因为它太容易了,团队根据厂商的宣传就切了过去,看不出明显差别,而且没有任何办法判断自己是改善了还是弄糟了。

在切换之前测,不是之后

没有基线就无法评估一次迁移,而基线必须在切换之前采集:

async function baseline(connection, samples = 200) {
  const results = [];
  for (let i = 0; i < samples; i++) {
    const submitSlot = await connection.getSlot();
    const sig = await sendRepresentativeTransaction(connection);
    const landed = await waitForLanding(sig);
    results.push(landed.slot - submitSlot);
    await sleep(1000);
  }
  results.sort((a, b) => a - b);
  return {
    p50: results[Math.floor(results.length * 0.5)],
    p90: results[Math.floor(results.length * 0.9)],
    p99: results[Math.floor(results.length * 0.99)],
  };
}

★有两条规则让这次测量保持诚实。★

测 slot 距离,不要测毫秒。 一次更快的往返,如果没有改变你落在哪个区块,就没有改变任何要紧的事。

在高负载下测,不要在清闲时段测。 ★网络平静时看起来一模一样的端点,在拥堵下会分化★ —— 而拥堵正是你的结果被决定的时候。

如果你测完发现差距在提交而不在读取,免费领个 BoltTx key 改一行就能拿来对比。

服务商之间实际差在哪

JSON-RPC 接口是标准的;围绕它的行为不是。

方面 差异所在
限流 ★按请求数 vs 按积分加权★
getProgramAccounts ★常被限制或禁用★
历史保留 近期 slot vs 数月
WebSocket 限制 每连接的订阅数
节点池同步 ★节点之间的 slot 偏差★
优先费数据 采样窗口与准确度

★带星的那两行造成了最多的迁移意外。★

按积分加权计费意味着,一个在某家限流内的请求量,可能在另一家直接爆掉 —— 因为 getProgramAccounts 的代价可能是 getBalance 的很多倍。

slot 偏差表现为余额看起来在倒退。不同服务商的节点池行为不同,在一个端点上从不需要 minContextSlot 的代码,换一家可能就需要了。

先并行跑两家

安全的迁移不是切换,是一段影子期:

// ★旧端点仍然是权威。新端点只做测量。★
const sig = await oldConnection.sendRawTransaction(raw, opts);

void newConnection
  .sendRawTransaction(raw, opts)          // ★相同字节 —— 安全★
  .then((s) => shadowMetrics.record(s))
  .catch((e) => shadowMetrics.recordError(e));

★把相同的已签名字节发给两个端点,不可能重复执行。★ 签名是同一个,而一个签名最多被收录一次 —— 所以第二次发送要么被网络丢弃,要么是通往同一次收录的更快路径。

这是唯一一种没有风险的并行提交,也是影子测试之所以可行的原因。为第二个端点重建交易就不安全了。

渐进切换

const useNew = hash(requestId) % 100 < rolloutPercent;
const conn = useNew ? newConnection : oldConnection;

分阶段推进 —— 先一小部分,再更多 —— 并且在每一步都比较两个样本群,而不是盯着看板凭感觉判断。

★切换完成之后,把旧端点继续配着。★ 两个都好的时候,按健康状况做故障切换不花任何代价,而它就是"某家服务商劣化"变成一次不便、还是变成一次故障的分界。

const endpoints = [primary, secondary];

for (const ep of endpoints) {
  if (!health.isHealthy(ep)) continue;
  try { return await ep.sendRawTransaction(raw, opts); }
  catch (e) { health.recordFailure(ep); }
}

把读取和发送分开

迁移是个好时机,可以不再把一个端点当成一件事。

★读取和发送的要求是相反的。★ 读取很重、有突发性、能容忍一个 slot 的陈旧;发送很小、对延迟敏感、绝不能被别的东西饿死。

共用一个端点意味着一次 getProgramAccounts 回填能耗尽你发送所需的配额 —— 而且恰好在你的机器人最忙的时候。把它们分开,消除掉的是一整类"在它发生之前完全不可见"的故障。

不该轻信什么

厂商的延迟数字。 通常是在有利条件下、对一个廉价调用测出的往返时间。★往返时间不是 slot 距离。★

清闲时段的对比。 唯一有意思的问题是拥堵下的表现。

你的第一个小时的数据。 缓存预热、连接池、DNS 都需要时间稳定下来。

平均值。 ★两个平均延迟完全一样的端点,尾部可能天差地别,而亏损住在尾部。★ 比 p90 和 p99。

上链应该是什么水平

我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。

★这是你该拿自己的测量结果去对照的基线。★ 如果在调完手续费和重试之后,你的分布仍然明显更宽,那剩下的差距是路由,而不是客户端配置。

BoltTx 在这里的位置

我们是一条发送路径,不是一个通用 RPC。所以我们是加在你现有配置之上,不是来替换它的。

读取、订阅、历史继续用你现在的服务商。只把 sendRawTransaction 指向我们,这是一行,而且可逆。提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前、传输途中观察不到。

你在本地签名。我们不托管资金、不代签、不修改交易内容 —— 所以拿相同字节和你当前的端点并行做影子测试是安全的。tip 带在交易里、从你自己的钱包链上支付,交易失败时跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。

免费领 API key,没有月费:

// 读取那边不用动。
const sender = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

常见问题

换 Solana RPC 服务商有多难? 代码改动只有一行,因为 JSON-RPC 接口是标准化的。真正的工作是衡量这次改动有没有帮上忙,而这需要一个在切换之前采集的基线。

对比 RPC 服务商时该测什么? "提交到落块"的 slot 距离,按 p50/p90/p99 看分布。 往返延迟说明不了你有没有赶上下一个区块,而那才是决定竞速胜负的东西。

能不切换就测试一家新服务商吗? 能。把相同的已签名字节发给两个端点,记录新端点的结果但不据此行动。相同字节产出同一个签名,所以这不可能重复执行。

把同一笔交易发给两家服务商安全吗? 安全,前提是字节完全相同。一个签名最多被收录一次,所以第二次提交要么被丢弃,要么是通往同一次收录的更快路径。

接口既然是标准的,服务商之间还差什么? 限流模型、getProgramAccounts 是否可用、历史保留时长、WebSocket 限制、节点池同步,以及优先费数据质量。接口一样,行为不一样。

迁移之后请求量为什么突然超限了? 很多服务商按加权积分而不是按请求数计费,所以重调用的代价远高于轻调用。同样的流量能装进一家的限额、却超出另一家的。

在新服务商上余额为什么看起来不一致? 节点池行为不同,连续请求可能打到处于不同 slot 的节点。把你见过的最高 slot 作为 minContextSlot 传进去,拒绝陈旧响应。

迁移完成后该保留旧服务商吗? 该,作为故障切换。两个都好的时候,按健康状况在两个已配置端点之间选择不花任何代价,它把一次服务商劣化从故障变成不便。

该多渐进地切换? 分阶段,每一步都比较两个样本群。按请求标识做百分比切分,能让你比较同类,而不是从看板上凭感觉判断。

读取和发送该用同一个端点吗? 最好不要。读取很重且有突发性,而发送对延迟敏感,所以共用端点会让一次回填在最糟的时刻耗尽发送所需的配额。

能相信服务商公布的延迟数字吗? 把它当作一个起点。它们通常报告的是有利条件下、对轻量调用的往返时间,而那和拥堵下的 slot 距离不是一回事。

对比该跑多久? 长到能覆盖拥堵时段,不只是一个清闲窗口。缓存、连接池和 DNS 也需要时间稳定,所以第一个小时不具代表性。

两个端点测试时一样、生产里为什么不一样? 因为测试通常发生在低负载下。端点在拥堵下才分化,而拥堵恰恰是你的成交率被决定的时候。

换服务商除了 URL 还要改代码吗? 发送路径通常不用。你可能需要为一致性加上 minContextSlot,或者在限流模型不同时调整并发,但客户端代码本身不变。

如果新服务商读取更快、发送不更快呢? 这很常见,也正是把两条路径分开有用的原因。你可以留下更快的读取、把发送路由到别处,而不用让一个决定牵制另一个。

怎么知道这次迁移真的有帮助? 在可比条件下,对比迁移前后的 slot 距离分布。 如果 p90 没变,那改善的东西并没有传导到你真正在乎的结果上。

延伸阅读

← 返回博客列表