Geyser gRPC - Best Practices

В этом руководстве собраны базовые паттерны для создания надежных production-ready приложений на Geyser gRPC. Solana Stream SDK поддерживает Geyser gRPC.

Начало работы

  • Начинайте с простого: сначала подпишитесь на slot updates, чтобы освоить streaming, и только потом добавляйте сложные filters.
  • Используйте filters осмысленно: подписывайтесь только на действительно нужные данные, чтобы снизить расход bandwidth/CPU. Vote transactions составляют примерно 70% трафика - исключайте их, если они вам не нужны.
rust
SubscribeRequestFilterTransactions {
    vote: Some(false),   // Exclude ~70% vote txs
    failed: Some(false), // Exclude failed txs
    ..Default::default()
}

Управление соединением

  • Автоматический reconnection: закладывайтесь на сетевые проблемы и переподключайтесь с exponential backoff.
  • Обработка ping/pong: Yellowstone gRPC servers отправляют ping. Всегда отвечайте pong, иначе сервер может закрыть соединение (это частая причина disconnect примерно через 30 секунд).
rust
if matches!(update.update_oneof, Some(UpdateOneof::Ping(_))) {
    subscribe_tx.send(SubscribeRequest {
        ping: Some(SubscribeRequestPing { id: 1 }),
        ..Default::default()
    }).await?;
}
  • Gap recovery: после переподключения используйте from_slot, чтобы избежать потери данных (duplicates допустимы).
rust
subscribe_request.from_slot = if tracked_slot > 0 {
    Some(tracked_slot) // Optionally subtract a small buffer to dodge reorgs
} else {
    None
};

Архитектурные паттерны

  • Разделяйте ingress и processing через channels, чтобы отделить network IO от business logic и добавить backpressure.
rust
let (tx, rx) = mpsc::channel::<SubscribeUpdate>(10_000);
// ingress task reads stream and tx.send(...)
// processing task consumes rx and does business logic
  • Используйте bounded channels: подбирайте capacity исходя из скорости обработки и допустимых потерь данных (меньше = меньше памяти, больше потерь; больше = больше памяти, меньше потерь).

Производительность и устойчивость

  • Отслеживайте processing latency и логируйте превышение порогов.
  • Батчируйте DB writes; выполняйте flush по размеру batch или по интервалу.
  • Для внешних вызовов используйте async IO; тяжелые вычисления выносите в worker tasks/threads.
  • Переиспользуйте subscription requests, чтобы уменьшить количество allocations.

Обработка ошибок

  • Разделяйте типы ошибок (stream vs processing vs channel).
  • Исправляйте невалидный запрос до повтора; используйте exponential backoff с учётом паузы только когда ответ допускает повтор.
  • Логируйте и отправляйте в metrics dropped updates, чтобы отслеживать slow-consumer conditions.

Исправляйте до повтора и используйте backoff с учётом паузы

Сохраните первую ошибку gRPC до того, как цикл переподключения её заменит. Запишите status и message, а также присутствующие metadata x-erpc-error-code, x-erpc-error-reason, x-erpc-doc-url, x-erpc-retry-after-seconds и x-erpc-retry-at. Раннее закрытие может выглядеть как общий transport error и не содержать все trailers.
Исправьте невалидный запрос, отклонённую форму filter или несоответствие регистрации IP до повтора. При паузе ERPC дождитесь возвращённого срока: он точнее локального backoff. Используйте ограниченный exponential backoff для сбоев доступности и других ответов, которые можно повторить. Не повторяйте неизменённый запрос только потому, что он вернул ненулевой status.

Использование ресурсов и мощность обработки

Защита Shared не даёт одной нагрузке потреблять capacity доставки, нужную другим клиентам ERPC. Stream может стать медленным из-за фактической пропускной способности, CPU, памяти, очереди consumer, записей в БД или внешних вызовов. Ресурсы должны соответствовать нагрузке; медленный получатель сам по себе не определяет ограничение.
Измерьте пиковую скорость данных у consumer. Переводите MB/s в Mbps через MB/s × 8 и оставляйте запас выше измеренного пика. Фиксированного неизмеренного минимума нет. Держите работу приёма короткой, передавайте updates в ограниченную очередь и масштабируйте или сужайте subscription, если обработка не успевает. Ограниченная очередь сдерживает память; она не решает проблему постоянно медленного consumer.

Работа с данными

  • Обрабатывайте duplicates при использовании from_slot (time-bounded cache или DB constraints).
  • Выбирайте commitment под вашу задачу:
    • processed: самые быстрые dashboards, возможен rollback
    • confirmed: хороший default для большинства apps/indexers
    • finalized: когда нужна максимальная определенность

Динамические subscriptions

Используйте bidirectional stream, чтобы обновлять subscriptions на лету (hot-swap filters, расширение покрытия) без reconnect.

Production checklist

  • ✅ Auto reconnection с exponential backoff
  • ✅ Gap recovery через from_slot
  • ✅ Обработка ping/pong (чтобы избежать disconnect через 30 секунд)
  • ✅ Разделение ingress и processing с bounded channels/backpressure
  • ✅ Error logging и metrics/alerting
  • ✅ Отслеживание processing latency
  • ✅ Обработка duplicates и оптимизация filters
  • ✅ Batch writes (если вы сохраняете данные)
  • ✅ Graceful shutdown и health checks

Дополнительные ресурсы