Geyser gRPC - 最佳实践

本指南涵盖构建健壮的生产就绪应用程序时使用 Geyser gRPC 的基本模式。Solana Stream SDK 支持 Geyser gRPC。

入门

  • 从简单开始:先使用 slot 订阅熟悉流处理,然后再添加复杂过滤器。
  • 明智使用过滤器:仅订阅您需要的数据以减少带宽/CPU 消耗。
rust
SubscribeRequestFilterTransactions {
    vote: Some(false),   // Exclude vote txs
    failed: Some(false), // Exclude failed txs
    ..Default::default()
}

连接管理

  • 自动重连:预期会有网络问题;使用指数退避进行重连。
  • Ping/pong 处理:Yellowstone gRPC 服务器会发送 ping。务必回复 pong,否则服务器可能关闭连接(约 30 秒断连的常见原因)。
rust
if matches!(update.update_oneof, Some(UpdateOneof::Ping(_))) {
    subscribe_tx.send(SubscribeRequest {
        ping: Some(SubscribeRequestPing { id: 1 }),
        ..Default::default()
    }).await?;
}
  • 间隙恢复:重连后使用 from_slot 避免数据丢失(允许重复)。
rust
subscribe_request.from_slot = if tracked_slot > 0 {
    Some(tracked_slot) // Optionally subtract a small buffer to dodge reorgs
} else {
    None
};

架构模式

  • 使用通道分离接收和处理,以解耦网络 IO 和业务逻辑并添加背压控制。
rust
let (tx, rx) = mpsc::channel::<SubscribeUpdate>(10_000);
// ingress task reads stream and tx.send(...)
// processing task consumes rx and does business logic
  • 使用有界通道:根据处理速度和数据丢失容忍度选择容量(较小 = 内存少,丢弃多;较大 = 内存多,丢弃少)。

性能和弹性

  • 监控处理延迟,超过阈值时记录日志。
  • 批量数据库写入;按批次大小或时间间隔刷新。
  • 对外部调用使用异步 IO;将繁重计算卸载到工作任务/线程。
  • 重用订阅请求以减少内存分配。

错误处理

  • 区分错误类型(流 vs 处理 vs 通道)。
  • 先修复无效请求再重试;仅当响应要求重试时,才使用能识别暂停的指数退避。
  • 记录/统计丢弃的更新以跟踪消费者过慢的情况。

先修复再重试,以及能识别暂停的退避

在重连循环覆盖第一条 gRPC 错误之前将其保留下来。记录其状态和消息,以及存在的 x-erpc-error-code、x-erpc-error-reason、x-erpc-doc-url、x-erpc-retry-after-seconds 和 x-erpc-retry-at 元数据。连接过早关闭时可能看起来像一般的传输错误,因此不一定包含每一个 trailer。
重试之前,请先修复无效请求、被拒绝的过滤器形式或 IP 注册不匹配。遇到 ERPC 暂停时,请等待返回的截止时间;它比本地退避更具体。对于可用性故障和其他可重试的响应,请使用有上限的指数退避。不要仅因为请求返回了非零状态,就反复重试未作修改的请求。

资源使用与处理能力

Shared 的保护机制可防止单个工作负载占用其他 ERPC 客户所需的投递能力。流变慢的原因可能是有效带宽、CPU、内存、消费端队列、数据库写入或外部调用。资源必须足以匹配工作负载;接收端变慢这一现象本身,并不能说明是哪一部分受到了限制。
请在消费端测量峰值数据速率。使用 MB/s × 8 将 MB/s 换算为 Mbps,并在测得的峰值之上留出余量。不存在未经测量的固定最低值。保持接收处理简短,将更新交给有界队列;如果处理跟不上,请扩展处理能力或缩小订阅范围。有界队列可以限制内存使用,但无法解决持续缓慢的消费端。

数据管理

  • 使用 from_slot 时处理重复数据(基于时间的缓存或数据库约束)。
  • 按使用场景选择确认级别:
    • processed:最快,适合仪表盘,可能回滚
    • confirmed:大多数应用/索引器的良好默认值
    • finalized:需要绝对确定性时使用

动态订阅

使用双向流在运行时更新订阅(热切换过滤器、扩大覆盖范围),无需重新连接。

生产检查清单

  • ✅ 带指数退避的自动重连
  • ✅ 使用 from_slot 的间隙恢复
  • ✅ Ping/pong 处理(避免 30 秒断连)
  • ✅ 使用有界通道/背压分离接收和处理
  • ✅ 错误日志和指标/告警
  • ✅ 处理延迟跟踪
  • ✅ 重复处理和过滤器优化
  • ✅ 批量写入(如有持久化需求)
  • ✅ 优雅关闭和健康检查

其他资源