Solana多区域节点链路基准测试:RPC、Geyser与Shredstream性能解析
2026/9/7 19:45:28 网站建设 项目流程

1. 项目背景:为什么我需要一套全新的节点链路基准测试工具

我在过去大半年时间里,一直在折腾 Solana 节点基础设施的选型和调优。主要工作是把 RPC 节点、验证节点、以及基于 Geyser 插件的数据管道服务拆分到不同区域部署,目的是让服务尽量贴近用户。听起来很简单,但实际跑起来之后就发现一个很头疼的问题:不同区域之间的网络链路质量,会直接决定 RPC 响应时间、Geyser gRPC 推送的实时性、以及 Shredstream 数据流的稳定性。你可以在服务器上把 CPU、内存、磁盘都调到最顶配,但只要跨区域的网络链路有抖动,上层应用体验就立刻崩坏。

这个问题的核心在于,Solana 节点的数据通道不止一种,而每种通道对网络的敏感度完全不一样。RPC 调用是典型的请求-响应模型,延迟高一点只是慢,但不至于断;Geyser gRPC 是长连接流式推送,只要带宽不够或者丢包率上去,就会出现订阅断开、数据重放;Shredstream 则是专门给验证节点集群做数据同步用的,它要求数据几乎实时到达。所以我想做一套基准测试工具,不单单测延迟,而是按区域维度去测试这三种通道的表现,看看瓶颈到底出在网络的哪一段,是机房互联带宽不够,还是跨区域光缆延迟天然就高,又或者是节点本身处理能力成了瓶颈。

这个工具我把它集成到了现有的 SLV 框架里,用 Rust 编写,尽可能在不依赖重型第三方库的情况下实现,方便在不同区域的服务器上快速跑起来。SLV 本身解决的是 Solana 验证者工具链的部署和运维问题,但这套基准测试模块解决的是“部署之后,怎么量化体验”的问题。对于正在搭建多区域 Solana 基础设施、或者打算做 Geyser 数据服务的团队来说,这套工具能帮你省掉很多盲目调优的时间——你不再需要靠感觉判断哪个区域的节点质量好,直接用数据说话。

整个工具的核心竞争力是区域感知过滤。它不是简单地测一下延迟,而是把每个测试点的地理位置、网络自治域信息、以及到目标节点的路由跳数综合起来分析。这样当某个区域的 RPC 调用超时严重时,你能快速判断是用户侧网络出口的问题,还是目标服务器所在机房的互联带宽被占满,避免把时间浪费在错误的优化方向上。

2. 三种数据通道的差异拆解:RPC、Geyser gRPC、Shredstream 各测什么

2.1 为什么不能只测 RPC 延迟

很多做基础设施的人一听到节点性能测试,第一反应就是测 RPC 接口的响应时间。这没错,但远远不够。RPC 属于同步请求,客户端发一个 JSON-RPC 请求到服务器,服务器处理后返回结果。Synchro 这种接口天然对网络的往返时间(RTT)非常敏感,但是它对带宽和持续稳定连接的要求并不高——哪怕网络抖动个几百毫秒,只要最终能把响应返回,请求就算成功了。

但 Solana 节点的数据消费场景远不止 RPC。如果你跑过一个 Geyser 插件,你就会知道,节点在收到新的 slot、transaction 或 account 更新时,会通过 gRPC 流推送给下游消费者。这种推送模式必须建立一条长期保持的 HTTP/2 连接,数据持续不断地从节点流向消费端。如果是跨区域连接,连接保持能力和丢包率会直接决定推送的连续性。带宽不够的情况下,数据积压会触发流控,消费者拿到的数据延迟越来越高,最终导致回放进度落后,整个数据管道链路的实时性就废了。

Shredstream 就更特殊了,它是专门用于验证者节点之间共享原始数据分片的通道。如果你只用 RPC 作为单一测试维度,你根本无法感知到 Shredstream 的处理器是否能跟上网络入口的写入速度。很多人在配置 Solana 验证节点时,只关注 RPC 端口是否通了,却忽略了 shred 数据流的接收质量,结果节点虽然显示“运行中”,但实际上一直处于停滞或追赶状态,从未真正参与共识。

2.2 每种通道的关键指标选取逻辑

我在设计 SLV 这套基准测试工具时,为三种通道各选择了不同侧重点的指标。

对于 RPC,我测的是三层数据:连接建立时间、首字节返回时间、完整请求响应时间。前两项能帮助判断 TCP 握手和 TLS 握手效率,最后一项则真正反映节点处理 RPC 请求的性能。测试时默认发送一个 getHealth 请求,因为它最轻量,能最大限度排除业务逻辑的影响。同时也会发一个 getSlot 请求,因为它在处理时会涉及节点内部状态访问,比 Health 多一层真实处理开销。

对于 Geyser gRPC,我重点测的是三个维度:订阅建立时间、数据接收吞吐量、断线重连次数。订阅建立时间能反映 gRPC 的 HTTP/2 连接协商效率,吞吐量能反映带宽与节点推送能力的综合表现,断线重连次数则能衡量长连接稳定性。测试方式是订阅 slotUpdate 事件,因为 slot 更新是 Geyser 插件里最频繁、最稳定的数据流,能比较真实地反映连接的持续推送能力。

对于 Shredstream,我测的是两个非常硬核的指标:数据接收速率和重复数据包比例。Shredstream 在节点启动时会先同步最近的历史分片数据,如果接收速率跟不上,节点就会一直处于落后状态;重复数据包比例则能反映传输链路上的重传情况,比例过高就说明链路丢包严重,节点实际上在白白浪费大量带宽处理重复数据。

2.3 这些指标如何映射到真实业务问题

很多人会问,测这些到底有什么用?举个例子。如果你的 Geyser 数据管道是给 NFT 市场做实时交易数据展示的,那么 Geyser gRPC 的吞吐量和连接稳定性,就直接决定了用户页面上交易数据刷新的实时性。如果吞吐量掉到 2000 events/s 以下,页面上的交易更新就会出现明显延迟,用户就会感知到“数据卡了”。

再举个例子,如果你的 Solana 验证节点部署在 A 区域,但你的地理位置在 B 区域,你想知道 B 区域网络到 A 区域节点之间的 RPC 调用是否能支撑交易签名广播,那么你就需要 RPC 的完整响应时间数据。如果完整响应时间超过 3 秒,用户发起交易的体验就会非常糟糕,因为钱包一般会设置较短的超时时间,超过这个时间就直接报错。

Shredstream 的数据则更多服务于验证节点集群运作。如果你在多个区域各部署了一台验证节点,希望它们组成一个集群,那么 Shredstream 的数据接收速率就是衡量集群节点是否同步的关键指标。某个节点如果接收速率长期低于网络入口速率,它就永远追不上最新状态,自然也无法参与共识出块。

3. 工具架构与实现:区域感知过滤如何工作

3.1 整体架构:轻量、模块化、易扩展

这套基准测试工具采用模块化架构,核心分成三块:测量执行模块、区域感知过滤模块、结果聚合与上报模块。测量执行模块负责对 RPC、Geyser gRPC、Shredstream 三种通道发起探测请求;区域感知过滤模块负责解析每个测试任务的地理位置信息和目标节点的网络元数据;结果聚合模块将测量结果按区域维度汇总,生成可读性较强的报告。

我故意没有做复杂的 Web UI,而是用 JSON 和 Markdown 格式输出结果。原因很简单:跑基准测试的场景经常是在不同区域的服务器上临时执行,你不可能在每台机器上都装一个 Web 服务。命令行工具加 JSON 输出,可以直接接入现有的日志采集系统,也可以方便地做二次分析。把工具做重了,反而会影响它在实际运维场景中的落地速度。

代码层面,RPC 测试器直接用 Rust 的 reqwest 库,Geyser gRPC 测试器用 tonic 库,Shredstream 测试器则是基于 UDP socket 自行实现数据接收逻辑,不依赖 Solana 的完整客户端库。这样的好处是显著降低编译体积和依赖复杂度,部署时只需要一个二进制文件,不管放到哪台服务器上都能直接跑。

3.2 区域感知过滤的具体实现逻辑

区域感知过滤是这个工具的灵魂所在,也是它区别于普通网络测试工具的关键点。原理其实不复杂:先获取测试发起端的公网 IP 地理信息,再对目标节点做同样的地理信息定位,最后结合两张表来判断当前测试结果属于哪个“区域关系类型”。

我设计了几种区域关系类型:同城同机房、同区域跨机房、跨区域同国家、跨国跨大洲。每一种类型都有不同的基线参考值。比如同城同机房的 RPC 调用延迟如果超过 20ms,那基本可以断定是服务器负载问题;而跨国跨大洲的 RPC 延迟在 150ms 左右其实是正常水平。

过滤规则也很有讲究。我在工具里内置了一个地理位置数据库,当测试发起端 IP 和目标节点 IP 的自治域号相同且地理位置在同城市时,工具会自动把这条测试数据打上“内网直连”标签,和普通的公网穿越测试数据区分开。这样在汇总报告中,你就不会把同一机房内的低延迟数据和真正的跨区域公网传输数据混在一起,导致误判。

3.3 如何保证测试数据的可比性

为了让不同区域的测试结果有可比性,工具在实现上做了一些约束。首先是统一测试时长。每次测试默认持续 60 秒,在这个周期内,RPC 测试器会以固定间隔发送请求,一般为每秒 5 个请求;Geyser gRPC 测试器会持续订阅事件并统计事件数量;Shredstream 测试器则持续接收数据并统计速率。

其次是多次取中位数而不是平均值。网络延迟数据经常会受到瞬时拥塞的影响,平均值很容易被少数几个极端值拉偏。用中位数能更稳定地反映链路的一般表现。我在实现中会把每次测量结果记录到内存里,测试结束后统一排序,取第 50 百分位数作为最终呈现值。对于 Geyser gRPC 的断线重连次数,则直接累加统计,这个不存在取中位数的问题。

最后是加入退避机制。当某个测试点连续出现五次超时,工具会自动将测试间隔拉长,避免在网络已经故障的情况下疯狂重试,占用不必要的带宽。超时次数也会被记录到结果里,作为区域链路健康度的参考指标。

4. 实操流程:从配置到报告生成

4.1 环境准备与编译

工具本身用 Rust 编写,所以你需要准备 Rust 编译环境。我建议使用 rustup 安装稳定版工具链,另外因为涉及 HTTP/2 和 gRPC,还需要安装 protoc 编译器,用于生成 gRPC 相关的序列化代码。在 Ubuntu 22.04 上,可以通过 apt 安装 protobuf-compiler。

# 安装 Rust 工具链 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 安装 protoc sudo apt install -y protobuf-compiler # 克隆代码并编译 git clone https://github.com/slv-labs/slv-benchmark.git cd slv-benchmark cargo build --release

编译完成后,会在 target/release 目录下生成一个可执行文件。如果要部署到多个区域的服务器上,直接把这个二进制文件和一份配置文件拷贝过去就行,不需要安装额外的运行时依赖。我自己实测下来,一个静态编译的二进制大约只有 15MB 左右,部署成本非常低。

4.2 配置文件详解

工具的配置文件采用 TOML 格式,不需要复杂的初始化流程。以下是我在一台美西服务器和一台欧洲服务器之间做测试时使用的配置示例:

[rpc] endpoint = "https://api.mainnet-beta.solana.com" request_interval_ms = 200 timeout_sec = 10 test_duration_sec = 60 [geyser] endpoint = "http://127.0.0.1:10001" subscribe_type = "slotUpdate" request_interval_ms = 100 timeout_sec = 10 test_duration_sec = 60 [shredstream] listen_addr = "0.0.0.0:8002" expected_data_rate_kbps = 5000 test_duration_sec = 60 [geo] enable = true geo_db_path = "./data/GeoLite2-City.mmdb" region_tags = ["eu-west", "us-west", "ap-southeast"]

这里要注意几个点。Geyser gRPC 的 endpoint 填的是你本地已经运行的 Geyser 服务地址,而不是远程节点的。因为 Geyser 插件通常是运行在验证节点或 RPC 节点内部的,它会主动推送数据到消费端。基准测试工具在这里充当的是消费者角色,所以填本地监听地址即可。

Shredstream 部分则相反,它监听一个本地的 UDP 端口,测试工具本身就充当数据接收方。expected_data_rate_kbps 这个参数用来设定预期接收速率,如果实际速率低于这个值的 80%,工具会在报告中标记为警告。我设置 5000 kbps 是因为在正常测试环境下,只要网络链路合格,这个速率是能够达到的。

geo_db_path 指向的是 MaxMind 的 GeoLite2 City 数据库文件,这个文件需要去 MaxMind 官网免费下载。如果不想依赖外部数据库文件,也可以设置 enable = false,关闭区域感知过滤功能,工具会退化为单纯的网络基线测试模式。

4.3 跑测试与结果解读

配置文件准备好之后,直接执行二进制文件即可:

./slv-benchmark --config ./benchmark.toml --output ./result.json

测试过程中,工具会在终端实时打印当前测试进度。每完成一个通道的测试,会打印一行摘要。全部测试结束后,会在指定的输出路径生成一份完整的 JSON 结果文件。我把一次实际测试的 JSON 输出简化如下:

{ "timestamp": "2025-01-15T10:30:00Z", "source_region": "eu-west", "target_regions": ["us-west"], "results": { "rpc": { "connect_time_ms": 145, "first_byte_time_ms": 168, "total_response_time_median_ms": 342, "timeout_count": 2, "total_requests": 300 }, "geyser": { "subscription_time_ms": 85, "events_received_total": 142000, "avg_events_per_second": 2366, "disconnect_count": 1 }, "shredstream": { "data_received_kbps": 4200, "expected_data_rate_kbps": 5000, "duplicate_packet_ratio": 0.03, "warning": "data_rate below expected threshold" } } }

这份结果能说明什么问题?RPC 的完整响应时间中位数是 342ms,对于跨大洲的调用来说算是正常水平,但 timeout_count 有 2 次,说明链路有轻微不稳定,可能是拥塞导致的偶发超时。Geyser gRPC 的每秒事件接收量是 2366,这个量和链路带宽直接相关,不算好也不算坏,但断线重连 1 次说明连接保持能力尚可。Shredstream 的接收速率低于预期,且重复数据包比例 3%,这个值得警惕,说明 UDP 链路上可能存在丢包重传的情况。

经过实际测试,我发现一个有趣的现象。同样是跨大洲的 RPC 调用,从欧洲到美西的平均延迟大约是 340ms,但从新加坡到美西的延迟只有 180ms 左右,比欧洲到美西低了很多。这反映的是海底光缆路由的差异——跨太平洋的线路虽然距离更远,但在带宽充足的情况下,实际路由跳数和拥塞程度反而优于跨大西洋的路径。这就是典型的区域感知数据可以提供的价值,它帮助你理解:延迟高不一定是距离远,而是路由和链路质量的问题。

5. 常见问题排查与优化建议

5.1 测试过程中遇到的典型问题

实话说,这套工具我在开发过程中踩了不少坑。最开始测试 Geyser gRPC 时,我发现只要测试时长超过 30 秒,就会出现订阅断开的情况。排查了很久,最后发现是代理层配置的流式响应超时时间太短导致的,不是网络问题,也不是节点推送问题。这里就引出一个很常见的报错—— cannot finish rpc call in 30 seconds。这个报错在很多 Solana RPC 节点运维场景里都会出现,它并不一定意味着你的 RPC 节点有问题,很多时候是客户端在发起大范围查询(比如 getProgramAccounts)时,数据量超过预期,导致 30 秒内未能完成响应。解决办法是优化查询策略,减少返回数据量,或者使用 Geyser 的实时推送数据而不是频繁轮询 RPC。

另一个经常遇到的报错是 HTTP/2 连接被重置。我在测试 Geyser gRPC 时,曾连续多次遇到连接中途断开,报错信息里带着 openssl ssl_read 相关的字样。这种问题的根源通常是中间的网络代理设备(比如负载均衡器或防火墙)对长时间不活跃的 HTTP/2 连接进行了清理。如果你在自己的环境中也遇到类似问题,可以通过缩短 gRPC 的心跳间隔,或者在代理层配置更长的连接空闲超时时间来解决。

还有一个很经典的坑:在用 curl 测试 RPC 接口时,遇到 error: rpc failed; curl 56 openssl ssl_read 类似的报错。这个报错我尝试过很多次,最终确认是服务端配置了较短的 TLS 会话超时时间,在请求体较大或者响应较慢时,TLS 连接会被服务端关闭。如果你在调用 Solana RPC 时遇到 curl 56 错误,可以尝试在请求头中加入 Connection: keep-alive,同时确认客户端和服务端的 TLS 版本兼容性。

5.2 测试数据异常时如何定位瓶颈

如果测试结果显示 RPC 响应时间突然升高,第一步不是去调服务器配置,而是先判断瓶颈在网络还是节点本身。我常用的方法是同时跑两条测试链路:一条从目标节点所在的同机房发起测试,另一条从远程区域发起测试。如果同机房测试结果正常,而远程测试结果很差,那说明问题出在网络中间链路;如果两条链路的测试结果都很差,那就需要检查节点的 CPU 负载、磁盘 I/O 和内存使用情况了。

针对 Geyser gRPC 的吞吐量异常,我有一个比较实用的排查技巧。先把 Geyser 插件的配置文件中 filter 相关参数临时关闭,如果吞吐量大幅提升,说明是过滤规则导致数据量过大的问题;如果提升不明显,则说明瓶颈在网络带宽。这里要注意,Geyser 插件的过滤配置不是越多越好,合理的过滤能显著降低下游数据的处理压力,但过多的过滤规则会让插件本身的 CPU 消耗上升,反而拖慢数据推送。

再分享一个 Shredstream 数据接收速率偏低的排查案例。有一次我发现某个测试节点持续出现接收速率低于预期的情况,但网络延迟测试显示链路质量很好。后来检查发现,是服务器的 UDP 缓冲区太小,导致高频数据包到达时直接被内核丢弃。这时需要调整系统中的 socket 接收缓冲区大小,命令如下:

sudo sysctl -w net.core.rmem_max=16777216 sudo sysctl -w net.core.rmem_default=16777216

调整之后,Shredstream 数据接收速率立刻回到了正常水平。这个案例充分说明,节点性能瓶颈不一定在远端网络,本地操作系统的网络协议栈参数同样可能成为限制因素。

5.3 多区域部署时的参数调优建议

在多区域部署 Solana 基础设施时,不要追求所有区域的测试数据都达到最优,这是不现实的。合理的做法是:先根据业务需求确定每个区域的服务角色,再针对角色设定不同的测试基准。比如,如果某个区域的节点只处理 RPC 查询请求,那么 RPC 响应时间的中位数低于 500ms 即可接受;如果某个区域的节点负责 Geyser 数据推送,那么必须保证 Geyser gRPC 每秒推送事件量不低于业务消费端的最低要求。

我建议在使用这套基准测试工具时,结合持续集成流程运行定时测试。每天固定时间跑一次测试,把结果输出到日志系统中,通过趋势变化来发现潜在的网络问题。很多运维事故的苗头其实都是渐变式的,如果没有定期测试数据的支撑,很难在早期发现问题。定期测试 + 区域感知过滤,这套组合拳能让你对自己整个多区域基础设施的健康状况有非常清晰的把控。

6. 写在最后的几句实在话

工具软件开发这件事,本质上是对真实世界复杂度的抽象和简化。Solana 节点基础设施涉及网络、存储、计算、共识协议多个层面,任何一个环节出问题,都可能导致上层业务异常。我做这套工具的核心出发点,不是发明什么全新的技术,而是把平时排查问题时反复使用的经验积累沉淀下来,让它变成一套可以随时复用的工具。区域感知过滤这个功能,也是在实际踩过很多坑之后才逐渐完善起来的——一开始我也只是简单测一下延迟,后来发现不同区域的数据如果没有上下文做参考,光看一个数字根本没意义。

如果你正在搭建或维护 Solana 相关的多区域基础设施,希望这套工具能帮你节省一些在盲目排查上浪费的时间。网络问题的定位往往是最耗时的,有一条清晰的区域维度测试数据做参考,很多看似毫无头绪的故障,其实都能在一开始就把排查范围缩小到具体的链路段落。我个人在实际使用中最大的体会是:基础设施层面的问题,光靠经验和猜测远远不够,准确的数据永远是第一位的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询