АрхитектураМикросервисы и интеграцииАрхитектор программного обеспечения

Команда заменила синхронный запрос между сервисами публикацией события. Какое ключевое изменение в согласов...

Команда заменила синхронный запрос между сервисами публикацией события. Какое ключевое изменение в согласованности данных должна принять бизнес-операция?

Проходите собеседования с ИИ помощником Hintsage

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

Переход от синхронного запроса к событию обычно переводит операцию из режима немедленной согласованности в режим временной, или eventual, согласованности. Изменение в одном сервисе может стать видимым в других позже, поэтому бизнес-процесс должен учитывать промежуточные состояния, задержки и возможный отказ доставки.

Событие фиксирует факт, произошедший в сервисе-источнике, но не означает, что все потребители уже обработали этот факт. Если бизнесу требуется немедленное подтверждение результата, полностью заменять синхронное взаимодействие событием нельзя без изменения самой модели операции.

Исторический контекст

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

Событийная интеграция появилась как способ разделить участников во времени. Сервис публикует факт локального изменения, а потребители обрабатывают его независимо, что помогает переживать кратковременную недоступность и масштабировать обработку.

Цена этого разделения — отсутствие единого мгновенного момента, когда все участники уже согласовали свои данные. Поэтому вместо простой транзакции между сервисами появляется распределённый бизнес-процесс.

Постановка проблемы

Пусть сервис заказов создал заказ и опубликовал событие для сервиса доставки. Событие может быть принято с задержкой, обработано позже либо временно не обработано из-за сбоя потребителя.

Если интерфейс сразу показывает пользователю, что доставка уже оформлена, он может сообщить неверное состояние. Дополнительные риски — повторная обработка события, нарушение порядка событий, частично выполненная операция и необходимость компенсировать уже совершённое действие.

Неверно считать публикацию события равнозначной завершению всего бизнес-процесса. Она подтверждает максимум локальный факт, надёжно зафиксированный источником, но не результат работы всех потребителей.

Подробное решение

Нужно явно разделить локальное состояние и состояние распределённого процесса. Например, заказ может иметь состояния создан, ожидает оформления доставки, доставка оформлена и оформление не удалось. Пользователь получает не ложное мгновенное подтверждение, а состояние процесса и понятные переходы.

Источник должен атомарно зафиксировать своё изменение и намерение опубликовать событие. Для этого применяют транзакционный журнал исходящих сообщений: запись о событии сохраняется в той же локальной транзакции, что и изменение бизнес-данных, а отдельный механизм доставляет её брокеру.

Потребитель должен обрабатывать событие повторно безопасно. Обычно для этого сохраняют идентификатор обработанного сообщения либо используют бизнес-ключ операции и проверяют, не выполнено ли действие ранее.

Нужно определить правила порядка событий. Если порядок важен, потребитель может проверять версию сущности или номер последовательности и откладывать событие, пришедшее раньше предшествующего состояния. Если строгий порядок не нужен, события следует проектировать так, чтобы обработка не зависела от их очередности.

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

Для необратимых действий полезен саговый процесс. Каждый шаг имеет локальную транзакцию, а при неудаче выполняется компенсирующее действие, например отмена резерва. Компенсация не всегда полностью возвращает прежнее состояние, поэтому критические ограничения нужно проверять до запуска процесса или оставлять синхронный шаг там, где требуется немедленная гарантия.

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

Ситуация из практики

Интернет-магазин после создания заказа должен зарезервировать товар на складе. Рассматривались три варианта.

Первый — синхронно вызвать складской сервис. Плюс решения — заказ сразу получает однозначный результат резерва. Минусы — задержка зависит от склада, а его недоступность напрямую мешает оформлению заказа.

Второй — отправить событие о создании заказа и сразу считать заказ подтверждённым. Это снижает связанность, но создаёт опасный разрыв: товар может закончиться, а пользователь уже получит обещание отгрузки.

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

Выбран третий вариант, потому что бизнес допускает небольшую задержку, но не допускает ложного подтверждения наличия товара. В итоге синхронным остался только быстрый ответ о принятии заказа, а окончательное состояние стало результатом наблюдаемого событийного процесса.

Что кандидаты часто упускают

  1. Вопрос: Является ли успешная запись события в брокер подтверждением завершения бизнес-операции?

Ответ: Нет. Это подтверждение того, что событие принято инфраструктурой доставки, но не того, что каждый потребитель его обработал и выполнил свою часть процесса. Даже после приёма сообщение может ждать обработки, завершиться ошибкой или потребовать повторной попытки.

Если бизнесу важно знать итог, потребитель должен публиковать отдельное событие результата либо процесс должен иметь доступное состояние, которое можно отслеживать. Ответ интерфейса должен различать принятое намерение, выполняемую операцию и успешно завершённый бизнес-процесс.

  1. Вопрос: Что произойдёт с согласованностью, если потребитель временно недоступен?

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

Для этого нужны надёжное хранение события, контроль необработанных сообщений и идемпотентность. Если сообщение потеряно или потребитель не умеет восстановить состояние, временная рассинхронизация превращается в постоянную, поэтому периодическая сверка и повторная публикация значимых фактов могут быть необходимы.

  1. Вопрос: В каком случае замена синхронного вызова событием ухудшит архитектуру?

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

Например, если перед подтверждением платежа нужно синхронно получить авторизацию внешней системы, асинхронное событие не должно создавать видимость окончательного успеха. В таком случае лучше оставить синхронную проверку, а последующие уведомления, обновление проекций и вторичные действия выполнять событийно.