Транспорт бэкенда
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?