Перейти к содержанию

API Composition

API Composition - способ выполнить запрос, которому нужны данные нескольких сервисов: composer вызывает сервисы-владельцы данных и склеивает их ответы в памяти. Зачем: у каждого сервиса своя БД, JOIN между ними нет, а фронт не знает топологию сервисов, должен быть один запрос - один собранный ответ.


Как работает

                  +-------------+ --> order-service    (заказ)
GET /order/42 --> |  Composer   | --> payment-service  (оплата)
                  |             | --> shipping-service (доставка)
                  +-------------+
                         |
                  in-memory join --> один ответ клиенту
  1. Composer получает запрос клиента.
  2. Вызывает сервисы-владельцы данных. Независимые вызовы идут параллельно. Если второму вызову нужен результат первого (id клиента из заказа), вызовы идут синхронно.
  3. Склеивает ответы в один объект.
  4. Если часть сервисов не ответила, отдаёт partial response: что собралось, а недоступное помечает.

Кто бывает composer

Composer Как Когда
API Gateway Маршрут собирает ответ из нескольких сервисов Простая склейка, одинаковая для всех клиентов
BFF Сборка под экраны одного клиента Клиенты разные, у каждого своя форма ответа
Отдельный aggregator-сервис Обычный сервис, который владеет запросом Сборка сложная или нужна нескольким потребителям
Клиент Фронт сам вызывает сервисы и склеивает ответы Почти никогда: лишние round-trip, клиент знает топологию сервисов

Gateway и composition - не одно и то же. Gateway отвечает за вход и роутинг, composition - за сборку ответа. Gateway часто умеет composition, но composer может быть и отдельным сервисом.


Грабли

  • Доступность падает с каждым вызовом. Composer нужен ответ всех сервисов: три сервиса по 99,9% вместе дают около 99,7%. Спасают partial response и fallback на необязательных частях.
  • Латентность. Параллельно - по самому медленному вызову, цепочкой - сумма всех. Ставь таймаут на каждый вызов.
  • N+1 по сети. Список из 10 000 заказов, где для каждого дёргается customer-service, так не собрать. Нужен batch-эндпоинт GET /customers?ids=... или read model.
  • Нет согласованного снимка. Каждый сервис отвечает из своей БД в свой момент, общей транзакции нет. Заказ уже отменён, а оплата ещё «прошла» - composer склеит и то и другое.
  • Фильтры и сортировка через границы. «Заказы клиентов из Казани по сумме» требуют данных двух сервисов сразу. Composer вытянет всё и отсортирует в памяти, на больших объёмах это не работает.

Когда composition не тянет

Тяжёлые запросы, сложные фильтры через границы, чтений намного больше, чем записей - тогда нужен CQRS: отдельная read model, которую заранее собирают из событий сервисов. Чтение из неё - один запрос, цена - eventual consistency. См. Запросы через границы сервисов.

API Composition CQRS read model
Когда собирается ответ на лету, при запросе заранее, из событий сервисов
Свежесть данных всегда актуальные с лагом, eventual consistency
Сложные фильтры и сортировка плохо, всё в памяти composer хорошо, схема заточена под запрос
Доступность нужны все вызываемые сервисы нужна только read model
Сложность низкая своё хранилище, подписка на события, пересборка

Итого: composition - самый простой способ собрать ответ из нескольких сервисов. Для простых запросов на разумных объёмах его хватает, тяжёлые чтения переезжают в read model.