Транспорт бэкенда
Как сервисы общаются
Netflix обрабатывает 2 миллиарда запросов в день между 700+ микросервисами. Один неверный выбор транспорта - и пользователь видит бесконечный спиннер вместо любимого сериала. gRPC на Protocol Buffers даёт сообщения в 3-5x меньше JSON и скорость в 3-10x выше. HTTP/2 мультиплексирование решает проблему head-of-line blocking HTTP/1.1. Envoy proxy в Kubernetes управляет этим трафиком как service mesh. Правильный выбор транспорта - не деталь реализации, это архитектурное решение.
- **gRPC + Protocol Buffers** - Uber (4000+ сервисов), Shopify, Netflix: бинарная сериализация в 3-5x меньше JSON, строгие типы, codegen; HTTP/2 мультиплексирование без head-of-line blocking
- **Envoy proxy (Istio/Linkerd)** - service mesh в Kubernetes; обрабатывает gRPC, load balancing, mTLS, observability между сервисами без изменения кода
- **Event Streaming (Kafka)** - Shopify обрабатывает пики продаж (12B за один день в BFCM) через событийную архитектуру; REST здесь не справился бы
Зачем нужен транспорт
Интернет-магазин. Всё в одном приложении - каталог товаров, корзина, оплата, доставка, уведомления. Монолит работает, пока команда маленькая. Но когда сервис вырос до миллиона пользователей, любое изменение в модуле оплаты может сломать каталог.
Решение - разбить монолит на отдельные сервисы. Каталог живёт отдельно, оплата отдельно, доставка отдельно. Но теперь возникает вопрос: **как эти сервисы будут общаться?** Раньше они вызывали функции напрямую в одном процессе. Теперь между ними - сеть. Uber использует gRPC для внутренней коммуникации между 4000+ микросервисами; Netflix - REST для публичного API и Kafka для внутренних событий.
**Inter-Process Communication (IPC)** - это общий термин для всех способов, которыми процессы обмениваются данными. В мире микросервисов IPC происходит по сети, и выбор транспорта напрямую влияет на надёжность, скорость и сложность всей системы.
От мейнфреймов к микросервисам
В 1970-х программы работали на одном мейнфрейме и общались через разделяемую память. В 1990-х появились CORBA и DCOM - первые попытки стандартизировать удалённые вызовы. В 2000-х пришёл SOAP, потом REST. Сегодня Netflix использует сотни микросервисов, обрабатывающих миллионы запросов в секунду - и за каждым стоит продуманный выбор транспорта.
Транспорт - это не просто «способ отправить запрос». Это архитектурное решение, которое определяет устойчивость к сбоям, скорость масштабирования, сложность поддержки. gRPC на Protocol Buffers - бинарная сериализация, сообщения в 3-5x меньше JSON, скорость 3-10x выше при высокой нагрузке. HTTP/2 мультиплексирование решает head-of-line blocking HTTP/1.1. Неправильный выбор транспорта - одна из самых дорогих ошибок в проектировании.
Почему переход от монолита к микросервисам создаёт проблему транспорта?
Синхронный vs асинхронный
Когда сервис A отправляет запрос сервису B, есть два принципиально разных сценария. **Синхронный**: A отправляет запрос и ждёт, пока B ответит. Как звонок по телефону - ты задаёшь вопрос и не кладёшь трубку, пока не получишь ответ.
**Асинхронный**: A отправляет сообщение и идёт дальше, не дожидаясь ответа. Как SMS - ты отправил, занимаешься своими делами, ответ придёт когда-нибудь (или не придёт вовсе, в модели fire-and-forget).
**Blocking** - поток выполнения останавливается и ждёт ответа. **Non-blocking** - поток продолжает работу. Синхронный вызов обычно blocking, асинхронный - non-blocking. Но бывают и исключения: async/await в коде выглядит синхронно, но под капотом не блокирует поток.
| Характеристика | Синхронный | Асинхронный |
|---|---|---|
| Связанность | Высокая (A знает о B) | Низкая (A знает только об очереди) |
| Время отклика | Сумма всех вызовов в цепочке | Только время отправки сообщения |
| Обработка ошибок | Немедленный ответ об ошибке | Нужен отдельный механизм (DLQ, retry) |
| Отладка | Просто - один поток | Сложно - распределённые события |
| Пример | HTTP GET /users/123 | Сообщение в RabbitMQ |
На практике большинство систем используют **оба подхода**. Запрос пользователя на получение профиля - синхронный (нужен ответ прямо сейчас). Отправка email после регистрации - асинхронная (пользователю не нужно ждать, пока письмо уйдёт).
Пользователь нажал «Купить». Нужно: 1) списать деньги, 2) отправить чек на email. Какой подход оптимален?
Обзор паттернов коммуникации
Синхронный и асинхронный - это способы взаимодействия. Но конкретных **технологий** для реализации этих способов - десятки. Разберём ключевые паттерны, каждый из которых решает определённый класс задач.
**RPC (Remote Procedure Call)** - вызов удалённой функции так, будто она локальная. Клиент вызывает `getUser(123)`, а под капотом запрос летит по сети. gRPC от Google - самая популярная реализация: бинарный Protocol Buffers (3-5x меньше JSON), HTTP/2 мультиплексирование (много запросов в одном соединении без head-of-line blocking), строгие типы, генерация кода. В Kubernetes Envoy proxy используется как service mesh для gRPC-трафика между сервисами.
**REST (Representational State Transfer)** - архитектурный стиль поверх HTTP. Ресурсы (users, orders) имеют URL, а операции выражаются через HTTP-методы (GET, POST, PUT, DELETE). Самый распространённый подход для публичных API.
**GraphQL** - клиент сам описывает, какие данные ему нужны. Один endpoint, гибкие запросы. Решает проблему over-fetching (получил больше, чем нужно) и under-fetching (пришлось делать 3 запроса вместо одного).
**Message Queue** - очередь сообщений: один отправитель, один получатель. Сообщение удаляется после обработки. Подходит для задач-команд: «отправь email», «обработай платёж».
**Event Streaming** - поток событий: один отправитель, много получателей. Сообщения хранятся в логе и могут быть перечитаны. Подходит для уведомлений: «заказ создан» - об этом хотят знать склад, аналитика, уведомления.
Границу между Message Queue и Event Streaming не всегда можно провести чётко. Kafka может работать как очередь, а RabbitMQ - как pub/sub. Но идеология разная: очередь - «обработай задачу», стриминг - «произошло событие».
Заказ создан. Об этом должны узнать: склад (зарезервировать товар), аналитика (обновить дашборд), email-сервис (отправить подтверждение). Какой паттерн подходит лучше всего?
Как выбрать транспорт
Вернёмся к нашему интернет-магазину с начала урока. Теперь, зная паттерны, мы можем принять конкретные решения. Но как выбрать? Нет единого «лучшего» транспорта - есть **подходящий для конкретной задачи**.
| Критерий | REST | gRPC | GraphQL | Message Queue | Event Stream |
|---|---|---|---|---|---|
| Латентность | Средняя | Низкая | Средняя | Высокая* | Средняя |
| Связанность | Средняя | Высокая | Низкая (клиент) | Низкая | Низкая |
| Типизация | Слабая (JSON) | Строгая (Protobuf) | Строгая (Schema) | Зависит от формата | Зависит от формата |
| Множество получателей | Нет | Нет | Нет | Ограничено | Да |
| Гарантия доставки | Нет (retry вручную) | Нет (retry вручную) | Нет | Да (ack) | Да (offset) |
| Отладка | Просто (curl) | Средне (grpcurl) | Средне (playground) | Сложно | Сложно |
Высокая латентность у Message Queue - относительное понятие. Речь о миллисекундах-десятках миллисекунд. Для фоновых задач это приемлемо, но для UI-ответа пользователю каждая миллисекунда на счету.
Практическое правило: **если нужен немедленный ответ** - синхронный транспорт (REST, gRPC, GraphQL). **Если результат не нужен прямо сейчас** - асинхронный (очередь, стрим). **Если получателей много** - Event Streaming.
Обрати внимание: в одной системе используются **четыре разных транспорта**. Это нормально. Хороший архитектор не выбирает один инструмент на все случаи жизни - он подбирает инструмент под задачу.
В следующих уроках мы подробно разберём каждый транспорт: начнём с фундамента (TCP/IP, сериализация), пройдём через HTTP и REST, углубимся в gRPC и GraphQL, а затем перейдём к message queue и event streaming.
REST подходит для всех задач - это универсальный стандарт
REST отлично подходит для публичных API и CRUD-операций, но для высоконагруженной внутренней коммуникации gRPC быстрее, а для событийной архитектуры нужны очереди и стримы
REST на HTTP/1.1 с JSON удобен для отладки (curl, Postman), но создаёт overhead. gRPC на Protocol Buffers + HTTP/2 даёт сообщения в 3-5x меньше JSON и скорость 3-10x выше при высокой нагрузке - именно поэтому Uber, Shopify, Netflix используют gRPC для внутренней коммуникации. HTTP/2 мультиплексирование решает head-of-line blocking HTTP/1.1 - несколько запросов в одном TCP-соединении без блокировки. А для паттерна «одно событие - много получателей» REST не предназначен вообще.
Ключевые идеи
- **Микросервисы = проблема транспорта**: function call (наносекунды) → сетевой вызов (миллисекунды + сбои + таймауты); Uber перешёл на gRPC для 4000+ сервисов
- **Синхронный** (REST, gRPC, GraphQL) - нужен немедленный ответ; **Асинхронный** (очереди, стримы) - результат может подождать
- **gRPC vs REST**: Protocol Buffers в 3-5x меньше JSON, скорость 3-10x выше; HTTP/2 мультиплексирование решает head-of-line blocking HTTP/1.1
- **Envoy proxy** - service mesh в Kubernetes, управляет gRPC/REST трафиком без изменения кода сервисов; Istio и Linkerd строятся на нём
- **Event Streaming** (Kafka): «одно событие - много подписчиков» без жёсткой связанности; Shopify пережил 12B BFCM-пик на событийной архитектуре
Связанные темы
Этот урок - отправная точка курса. Каждый упомянутый транспорт будет детально разобран:
- TCP/IP и OSI — Фундамент, по которому работают все транспорты
- Сериализация — Как данные превращаются в байты для передачи по сети
- REST — Самый распространённый синхронный паттерн
Вопросы для размышления
- Uber использует gRPC для 4000+ микросервисов, но публичный API - REST. Почему для внутренней коммуникации выбран gRPC, а не REST, и что именно даёт Protocol Buffers + HTTP/2 мультиплексирование по сравнению с JSON + HTTP/1.1?
- Shopify пережил 12B продаж за один день на событийной архитектуре с Kafka. Почему синхронный REST (каждый сервис вызывает каждый) не справился бы с таким пиком нагрузки?
- Envoy proxy в Kubernetes управляет gRPC-трафиком как service mesh без изменения кода сервисов. Что это означает с точки зрения разделения ответственности между transport layer и application layer?
Связанные уроки
- bt-02-osi-tcp — OSI model and TCP deep dive follow directly from the transport overview
- net-01-intro — Backend transport protocols build on top of networking layer fundamentals
- st-01-feedback-loops — TCP acknowledgment mechanism is a textbook feedback loop
- alg-01-big-o — Protocol selection is a complexity analysis: HTTP/2 multiplexing vs HTTP/1.1 head-of-line blocking
- sd-01-intro — System design components communicate through the transport protocols surveyed here
- net-15-tcp-basics