← Назад к проектам

AI API Gateway: единая инфраструктура доступа к провайдерам

> Закрытый репозиторий. Доступен для code review по запросу.

▍ Проблематика

Организации, использующие несколько провайдеров больших языковых моделей (OpenAI, Anthropic, Google и др.), сталкиваются с системными инфраструктурными проблемами:

  • Фрагментация протоколов: Каждый провайдер имеет собственный формат запросов/ответов, семантику streaming (SSE), обработку ошибок и модель аутентификации.
  • Планирование ёмкости провайдеров: Лимиты провайдеров и целевые уровни сервиса требуют compliant routing, мониторинга ёмкости и graceful degradation до наступления перегрузки.
  • Непредсказуемые задержки: Фазы «обдумывания» (thinking) у frontier-моделей длятся до 2-3 минут, вызывая idle timeout disconnects на уровне балансировщиков.
  • Отсутствие единого observability: Объём использования, latency-распределение, error rates — разрозненные метрики без единого контроля.

Бизнесу требуется единый шлюз (Gateway), предоставляющий унифицированный OpenAI-совместимый API, прозрачную маршрутизацию между провайдерами, устойчивость к сетевым аномалиям и строгую консистентность распределённого состояния между узлами.

▍ Архитектура

Система представляет собой высоконагруженный reverse-proxy и API-шлюз, написанный полностью на Rust. Cargo workspace: 15+ крейтов, чёткое разделение на domain/infra/api слои.

┌─────────────────────────────────────────────────────────┐
│                     CLIENTS                             │
│         (OpenAI SDK, curl, любой HTTP-клиент)           │
└───────────────────────┬─────────────────────────────────┘
                        │ OpenAI-compatible API
                        ▼
┌─────────────────────────────────────────────────────────┐
│                   GATEWAY LAYER                         │
│  ┌──────────┐  ┌──────────────┐  ┌───────────────────┐  │
│  │ Protocol │  │   Session    │  │  Load Balancer    │  │
│  │ Adapter  │  │   Affinity   │  │  (least-loaded)   │  │
│  │ (transl.)│  │   Manager    │  │                   │  │
│  └────┬─────┘  └──────┬───────┘  └────────┬──────────┘  │
│       │               │                   │             │
│  ┌────▼───────────────▼───────────────────▼──────────┐  │
│  │              STATE LAYER                          │  │
│  │  ArcSwap (lock-free config)  +  CRDT/LWW sync     │  │
│  │  PostgreSQL (Event Sourcing + streaming replica)  │  │
│  └───────────────────────────────────────────────────┘  │
└───────────────────────┬─────────────────────────────────┘
                        │ Managed connection pool
                        ▼
┌─────────────────────────────────────────────────────────┐
│               UPSTREAM PROVIDERS                        │
│     OpenAI    │    Anthropic    │    Google    │  ...   │
└─────────────────────────────────────────────────────────┘

Ключевые компоненты:

  • Protocol Adapter: двунаправленная трансляция форматов (OpenAI ↔ проприетарные API провайдеров). Клиенты работают через единый OpenAI-совместимый интерфейс, независимо от того, какой провайдер обрабатывает запрос.
  • Session Affinity Manager: персистентная привязка «клиентская сессия → upstream provider», выживающая после рестартов сервиса. Улучшает cache locality и обеспечивает предсказуемое поведение для stateful-диалогов.
  • Load Balancer: least-loaded routing с защитой от thundering herd при первичном назначении сессии. Балансирует трафик между утверждёнными интеграциями провайдеров и сохраняет целевые уровни сервиса.
  • State Layer: `ArcSwap` для lock-free горячей перезагрузки конфигурации (zero contention на hot path). CRDT/LWW с tombstone-записями для синхронизации состояния между узлами. PostgreSQL с Event Sourcing и потоковой репликацией как единый источник истины.
  • Managed Connection Pool: RAII-контролируемый пул соединений с агрессивным HTTP/2 keepalive для предотвращения idle timeout disconnects во время длительных фаз генерации.

Инфраструктура:

  • Frontend: Административный дашборд на Rust (Leptos + WASM) — real-time мониторинг, управление аккаунтами, аналитика расходов.
  • DevOps: Nix Flakes (воспроизводимые сборки) + systemd socket activation (zero-downtime deploy).

▍ Метрики (Production Data)

Система работает под реальной производственной нагрузкой:

OpenAI-compatible
Клиентский интерфейс
3+ утверждённых
Интеграции провайдеров
zero downtime
Непрерывность деплоя
multi-node CRDT
Консистентность состояния
~94%
Целевая доступность
graceful SSE close
Обработка сбоев
централизованная аналитика
Прозрачность расходов
real-time dashboard
Админ-поверхность
наблюдаемость + контроль
Production ownership

▍ Ключевые инженерные решения

Проблема
Ёмкость провайдеров, routing state и session state должны быть консистентны между узлами без центрального координатора.
Решение
LWW (Last-Write-Wins) CRDT с tombstone-записями. Узлы реплицируют состояние независимо; конфликты разрешаются по временной метке. Tombstones предотвращают «воскрешение» удалённых записей при merge.
Отвергнутая альтернатива
Raft/Paxos — избыточная сложность для eventually-consistent workload; CRDT не требует leader election.
Проблема
Конфигурация (список провайдеров, квоты, routing rules) меняется в runtime. Классический RwLock создаёт contention при тысячах конкурентных запросов.
Решение
ArcSwap — атомарная замена Arc<Config> без блокировок. Читатели получают snapshot за O(1), writer публикует новую версию атомарно. Zero contention на hot path.
Проблема
При обрыве upstream-соединения во время SSE streaming, клиент получает незавершённый поток — ломает парсинг на стороне SDK.
Решение
Gateway перехватывает сетевую ошибку и генерирует синтетический `[DONE]` chunk с `finish_reason: "error"`, конвертируя транспортный сбой в штатное завершение потока. Клиентский код обрабатывает это как обычное завершение, а не как exception.
Проблема
Frontier-модели «думают» 60-180 секунд. Upstream-балансировщики разрывают idle-соединения по timeout (30-60s), хотя запрос ещё обрабатывается.
Решение
Агрессивный HTTP/2 PING keepalive на уровне мультиплексора. Поддерживает соединение активным в глазах промежуточных load balancers, не мешая работе модели.
Проблема
Stateful-диалоги с провайдерами выигрывают от cache locality. Случайное переключение upstream повышает вариативность стоимости и делает длинные диалоги менее предсказуемыми.
Решение
Персистентная привязка «клиентская сессия → upstream provider», сохраняемая в PostgreSQL. Выживает после рестартов. При назначении новой сессии — least-loaded алгоритм с защитой от thundering herd.

▍ Технологический стек

Backend
Rust, Axum, Tokio, SQLx, PostgreSQL, ArcSwap, DashMap
Frontend
Rust, Leptos, WebAssembly (WASM)
DevOps
Nix (Flakes), Systemd (socket activation), Podman

▍ Что демонстрирует этот проект

Системная архитектура
Проектирование распределённого stateful-сервиса, устойчивого к сетевым аномалиям, partial failures и длительным задержкам upstream.
Распределённые системы
Практическое применение CRDT, Event Sourcing и потоковой репликации PostgreSQL в production.
Performance Engineering
Lock-free hot path, zero-copy streaming, управление пулами соединений без утечек под постоянной нагрузкой.
Production Operations
Zero-downtime deploy, глубокая инструментация (метрики, трейсинг), graceful degradation при отказах upstream-провайдеров.
Rust Ecosystem Mastery
Workspace из 15+ крейтов, type-safe domain model и exhaustive pattern matching на границах отказов.

Готовы построить нечто подобное?

Начать проект