Транспорт бэкенда

Decision Matrix: какой транспорт выбрать

Senior engineer получает задачу: 'добавить real-time уведомления'. Junior выбирает WebSocket потому что 'это для real-time'. Senior тратит 30 минут на Decision Matrix и выбирает SSE - потому что однонаправленный поток, simpler scaling, автоматический reconnect. Правильный вопрос не 'что такое WebSocket', а 'зачем именно WebSocket здесь'.

  • **Uber** использует 5 разных транспортов в одном trip flow: REST (API Gateway), gRPC (internal services), Kafka (events), WebSocket (driver location), Redis Pub/Sub (ephemeral broadcast) - каждый в своей роле
  • **Stripe** публичный API - REST несмотря на огромный масштаб, потому что developer experience важнее micro-оптимизаций. Internal services - gRPC для строгого контракта
  • **LinkedIn** Activity Feed migration с REST на Kafka (2013) заняла 18 месяцев. 80% времени - организационные изменения (200+ consumers, monitoring, runbooks), только 20% - техническая работа

Decision Dimensions

Выбор транспортного протокола - не вопрос предпочтений, а engineering decision с чёткими trade-offs. Пять ключевых измерений: **Latency** (P99 < 10ms? < 100ms? допустимо минуты?), **Throughput** (1K/s? 1M/s?), **Durability** (at-most-once vs at-least-once vs exactly-once), **Ordering** (глобальный порядок или per-key достаточно?), **Coupling** (сервис должен знать о получателе или нет?).

Coupling - часто забытое измерение. REST требует чтобы caller знал URL и availability получателя. Kafka decouples: producer не знает о consumers и не зависит от их uptime. Это не значит что Kafka всегда лучше - loose coupling сложнее для debugging, трассировки и понимания потока данных. Uber для internal microservices использует gRPC (tight, но явный контракт), Kafka для cross-domain events.

Платёжный сервис вызывает fraud-detection синхронно перед одобрением транзакции. Fraud-detection падает на 10 секунд. Какое измерение Decision Matrix критично?

Sync Decision Tree

Синхронная коммуникация (REST/gRPC) оправдана когда: caller нужен результат прямо сейчас (пользователь ждёт ответ), операция требует immediate confirmation (payment authorization), или latency критична (<10ms). gRPC выбирается над REST когда: internal microservices, bi-directional streaming нужен, строгий контракт важнее human-readability, или нужна мультиплексация через HTTP/2.

Pitfall: команды выбирают gRPC 'потому что быстрее', но не учитывают operational overhead. gRPC требует: Protobuf-компилятор в CI, proto files shared между сервисами (proto registry), отладка сложнее (нет curl), browser clients требуют gRPC-Web прокси. Stripe, несмотря на огромный масштаб, использует REST для public API именно из-за developer experience.

Mobile app загружает user profile при открытии. Нужен: user data + recent orders + recommendations. Какой подход правильный?

Async Decision Tree

Асинхронная коммуникация оправдана когда: caller не ждёт результат немедленно, операция занимает секунды/минуты, нужна гарантированная доставка при недоступности получателя, или нужен fan-out (один event, много обработчиков). Выбор между Kafka, RabbitMQ, NATS определяется retention, ordering, throughput и replay requirements.

NATS JetStream (2021) заполнил gap: NATS всегда был быстрым (10M msg/s) но без persistence. JetStream добавил streams с retention policy и at-least-once delivery. Cloudflare использует NATS для internal messaging между PoP (2000+ точек присутствия) - Kafka операционно слишком тяжёл для edge nodes с ограниченными ресурсами.

Стартап строит email-маркетинг: user выполняет action -> триггерится последовательность emails (день 1, 3, 7). Какой брокер?

Hybrid Architectures

Real-world системы используют несколько протоколов одновременно. E-commerce checkout: REST для user-facing API (payment form), gRPC между inventory/payment/fraud сервисами, Kafka для post-purchase events (analytics, email trigger, loyalty points), Redis Pub/Sub для real-time inventory updates на фронтенде. Каждый протокол в своей роле, а не один на всё.

Anti-pattern: 'Kafka для всего'. Команда видит успех Netflix/Uber с Kafka и переводит на Kafka даже синхронные user-facing запросы. Результат: user делает POST /order, ответ 200 'accepted', затем polling GET /order/{id} пока статус не изменится. UX деградирует. Kafka оправдан для post-processing, не для primary request-response flow где пользователь ждёт.

После успешного payment: нужно обновить inventory, начислить loyalty points, отправить receipt email, обновить fraud model. Какая архитектура правильная?

Migration Strategies

Миграция транспорта в production - не big bang замена, а постепенный переход. Strangler Fig Pattern: новый транспорт обслуживает новые запросы, старый постепенно выводится. Expand-Contract (Parallel Change): сначала добавить новый endpoint/channel, затем мигрировать clients, затем удалить старый. Темп: 1% трафика -> 10% -> 50% -> 100%, откат за 5 минут при аномалиях.

Linkedin мигрировал с REST на Kafka для activity feed в 2013 году - это заняло 18 месяцев и 3 фазы. Не потому что технически сложно, а потому что нужно было изменить 200+ consumers, мониторинг, alerting, runbooks. Техническая миграция - 20% работы. Organizational migration - 80%.

Нужно выбрать один правильный протокол для всего проекта и придерживаться его

Зрелые системы используют 4-5 протоколов одновременно: REST для public API, gRPC для internal sync calls, Kafka для async events, WebSocket для real-time, Redis Pub/Sub для ephemeral broadcast

Каждый протокол оптимизирован под свой use case. Принудительное использование одного протокола везде создаёт либо избыточный complexity (Kafka для simple request-response), либо ненадёжность (REST для high-volume events без replay)

При миграции REST->Kafka обнаружено что 0.3% событий приходят out-of-order (партиция по random UUID вместо user_id). Какое минимальное изменение исправит это?

Итоги

  • **5 измерений** для любого решения: latency, throughput, durability, ordering, coupling - каждое измерение указывает на оптимальный протокол, конфликты между измерениями требуют conscious trade-off
  • **Hybrid по умолчанию**: production системы используют несколько протоколов. Sync для user-facing request-response, async для post-processing fan-out. 'Kafka для всего' - anti-pattern
  • **Migration = Strangler Fig**: dual write -> shadow mode -> compare -> cut over -> cleanup. Big bang замена протокола в production - рецепт инцидента

Связанные темы

Decision Matrix применяет знания из всего курса:

  • Backpressure — Выбор async broker учитывает backpressure механизмы: Kafka consumer lag как сигнал, RabbitMQ prefetch для flow control
  • Benchmarking — Decision Matrix требует данных: benchmarking инструменты (wrk, ghz) дают реальные latency/throughput цифры для сравнения протоколов в конкретной инфраструктуре
  • Saga Pattern — Saga - hybrid паттерн: sync начало workflow + async compensating transactions. Decision Matrix помогает выбрать orchestration (gRPC Temporal) vs choreography (Kafka events)

Вопросы для размышления

  • Стартап выбрал Kafka для всех коммуникаций включая пользовательские запросы. Через год команда жалуется на сложность debugging и плохой UX (пользователи не получают мгновенный feedback). Как провести аудит и предложить гибридную архитектуру без полного переписывания?
  • Decision Matrix говорит 'используйте gRPC для internal services'. Но команда из 5 человек, у всех опыт только с REST. Как взвесить технический optimal выбор против operational capability команды?
  • Компания мигрирует с монолита на microservices. Монолит использует in-process function calls (нет network). При переходе на network calls: какой протокол выбрать и как quantify latency regression impact на user experience?

Связанные уроки

  • net-15-tcp-basics
Decision Matrix: какой транспорт выбрать

0

1

Войти