Geyser gRPC - 最佳实践

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

入门

  • 从简单开始:先使用 slot 订阅熟悉流处理,然后再添加复杂过滤器。
  • 明智使用过滤器:仅订阅您需要的数据以减少带宽/CPU 消耗。投票交易约占流量的 70%——如果不需要就排除它们。
rust
SubscribeRequestFilterTransactions {
    vote: Some(false),   // Exclude ~70% 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 通道)。
  • 重连使用指数退避(从小值开始,设置合理上限)。
  • 记录/统计丢弃的更新以跟踪消费者过慢的情况。

数据管理

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

动态订阅

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

生产检查清单

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

其他资源