---
title: "Geyser gRPC - 最佳实践"
description: "生产级 Geyser gRPC 客户端的基本技巧，包括 ping/pong、重连和过滤器。Solana Stream SDK 支持 Geyser gRPC。"
canonical: "https://erpc.global/zh/doc/geyser-grpc/best-practices/"
locale: "zh"
---

# 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 秒断连）  
- ✅ 使用有界通道/背压分离接收和处理  
- ✅ 错误日志和指标/告警  
- ✅ 处理延迟跟踪  
- ✅ 重复处理和过滤器优化  
- ✅ 批量写入（如有持久化需求）  
- ✅ 优雅关闭和健康检查

## 其他资源

- Solana Stream SDK（Geyser gRPC 支持）：https://github.com/ValidatorsDAO/solana-stream
