Синхронные и асинхронные интеграции, форматы обмена

Синхронно или через очередь — выбор, который аналитик обосновывает на каждой второй интеграции, и вопрос, который любят задавать на позицию middle+.

Синхронная интеграция — вызывающая сторона ждёт ответа и не может продолжить без него. Асинхронная — отправитель кладёт сообщение и продолжает работу, а получатель обработает его позже.

Вопрос 1. Когда вы выберете очередь, а когда синхронный вызов?

Что проверяют. Умение обосновать выбор компромиссами, а не модой. Ответ «микросервисы же, значит Kafka» — провал.

КритерийСинхронно (REST/gRPC)Асинхронно (очередь/событие)
Нужен ответ прямо сейчасда: проверка баланса, авторизация платежанет: начисление бонусов, отправка письма
Пиковые нагрузкиперегружают получателяочередь сглаживает пик
Получатель временно недоступеноперация падаетсообщение подождёт в очереди
Сложность отладкиниже: видно вызов и ответвыше: нужны корреляционные идентификаторы
Согласованностьсразув конечном счёте (eventual)
Связанность системвысокаянизкая: издатель не знает подписчиков

Правило, которое хорошо звучит на собеседовании: синхронно — то, без чего пользователь не может продолжить прямо сейчас; асинхронно — всё остальное, особенно то, что порождает эффекты в других системах. Оформление заказа: проверка оплаты — синхронно, уведомление клиента, начисление бонусов, резерв на складе и передача в аналитику — событиями.

Вопрос 2. Что нужно описать в требованиях к асинхронной интеграции?

Что проверяют. Знаете ли вы, что очередь приносит собственный набор проблем, и умеете ли вы заранее закрыть их требованиями.

  • Гарантия доставки. Почти все брокеры дают at-least-once: сообщение может прийти дважды. Значит, обработчик обязан быть идемпотентным — по идентификатору события. «Ровно один раз» на практике достигается именно так, а не магией брокера.
  • Порядок. Гарантируется обычно только внутри партиции или очереди с одним ключом. Если важен порядок событий по заказу — ключом партиционирования делают идентификатор заказа.
  • Повторы и dead letter queue. Сколько раз пробуем, с какой задержкой, куда складываем неразобранное и кто это разбирает.
  • Схема сообщения и её эволюция. Контракт события — такой же контракт, как API.
  • Срок хранения и объём. Сколько живут сообщения, что происходит при переполнении.
  • Наблюдаемость. Сквозной correlationId через все сервисы, иначе разобрать инцидент невозможно.

Контракт события удобно описывать так же строго, как REST-метод:

{
  "eventId": "8f2a41d0-6b7e-4f10-9a37-1b1c5f8e2ab9",
  "eventType": "order.created",
  "version": 1,
  "occurredAt": "2026-03-01T10:15:32Z",
  "correlationId": "req-2f9c11a4",
  "producer": "order-service",
  "payload": {
    "orderId": 1024,
    "customerId": 7,
    "total": 3650.00,
    "currency": "RUB",
    "items": [
      { "productId": 15, "qty": 2, "price": 450.00 },
      { "productId": 42, "qty": 1, "price": 2750.00 }
    ]
  }
}

Поля eventId (для дедупликации у потребителя), version (для эволюции схемы) и correlationId (для сквозной трассировки) — то, что забывают чаще всего, а спрашивают почти всегда.

Вопрос 3. JSON, XML или protobuf — как выбрать формат обмена?

Что проверяют. Знаете ли вы сильные стороны каждого, а не только тот, с которым работали.

ФорматСильные стороныГде применяют
JSONчитаем, прост, поддержан везде, схема через JSON Schema или OpenAPIпубличные и внутренние REST API, события
XMLстрогая схема XSD, пространства имён, подпись документа, вложенные структуры и атрибутыгоссистемы, банки, SOAP, обмен документами, ЭДО
protobufбинарный, компактный, схема обязательна, кодогенерация, быстрыйgRPC между сервисами, высоконагруженные потоки

Пример одного и того же заказа в XML со схемой — типичный вид интеграции с регулируемой системой:

<?xml version="1.0" encoding="UTF-8"?>
<Order xmlns="urn:shop:order:1.0" id="1024">
  <Customer id="7">Анна Петрова</Customer>
  <CreatedAt>2026-03-01T10:15:32Z</CreatedAt>
  <Items>
    <Item productId="15" qty="2" price="450.00"/>
    <Item productId="42" qty="1" price="2750.00"/>
  </Items>
  <Total currency="RUB">3650.00</Total>
</Order>

И тот же контракт в виде схемы protobuf — обратите внимание, что номера полей часть контракта: их нельзя переиспользовать после удаления поля.

syntax = "proto3";

message Order {
  int64  id          = 1;
  int64  customer_id = 2;
  string created_at  = 3;
  repeated Item items = 4;
  string currency    = 5;
  double total       = 6;
}

message Item {
  int64  product_id = 1;
  int32  qty        = 2;
  double price      = 3;
}

Практический ответ: JSON по умолчанию; XML — когда так требует внешняя регулируемая сторона или нужна подпись документа; protobuf — когда критичны объём трафика и скорость и обе стороны внутренние.

Типичные ошибки кандидатов

  • Выбирают очередь «для развязки», не задумываясь, что пользователю всё равно нужен ответ здесь и сейчас.
  • Считают, что брокер гарантирует ровно одну доставку, и не требуют идемпотентности потребителя.
  • Не описывают retry-политику и dead letter queue — потерянные сообщения обнаруживаются в проде.
  • Полагаются на глобальный порядок сообщений, которого у брокера нет.
  • Забывают про версию схемы события и потом ломают всех потребителей одним полем.
  • Считают XML «устаревшим»: в госинтеграциях и ЭДО он стандарт де-факто, и подпись документа проще сделать именно в нём.

Как ответить кратко

Синхронно делаю то, без чего пользователь не может продолжить: авторизация платежа, проверка остатка. Всё остальное — событиями: уведомления, бонусы, аналитика, потому что очередь сглаживает пики и переживает недоступность получателя, ценой отложенной согласованности и более сложной отладки. Для асинхронной интеграции обязательно фиксирую в требованиях: доставка at-least-once, поэтому потребитель идемпотентен по eventId; порядок гарантируется только по ключу партиционирования; политика повторов и dead letter queue; версия схемы события и сквозной correlationId. Формат по умолчанию JSON, XML — если так требует внешняя регулируемая сторона или нужна подпись, protobuf — для внутренних высоконагруженных вызовов.

Проверьте себя
1. Какую операцию при оформлении заказа разумнее сделать синхронной?
AНачисление бонусных баллов
BОтправку письма клиенту
CАвторизацию платежа
DПередачу данных в аналитическое хранилище
2. Брокер даёт гарантию at-least-once. Что из этого следует для требований?
AПотребитель обязан быть идемпотентным, обычно по eventId
BСообщения гарантированно не потеряются и не продублируются
CПорядок сообщений гарантирован глобально
DОбработчик можно писать без обработки ошибок
3. В каком случае обоснованно выбрать XML вместо JSON?
AКогда нужен максимально компактный бинарный формат
BКогда обмен идёт с госсистемой или требуется подпись документа и строгая схема XSD
CКогда обе стороны — внутренние высоконагруженные сервисы
DXML устарел и обосновать его выбор нельзя