Как организовать гарантированную отправку сообщений в хореографии — паттерн Outbox

Как организовать гарантированную отправку сообщений в хореографии — паттерн Outbox

При реализации межсервисного взаимодействия с использованием хореографии часто возникает вопрос — как гарантировать доставку сообщений из одной системы (сервиса) в другую?

Предположим такую ситуацию:

Сервис обрабатывает входящий запрос или сообщение, потом сохраняет или обновляет данные в БД и отправляет сообщение. Если возник сбой на каком-то этапе, то могут произойти следующие ситуации:

  1. Данные сохранены, транзакция закрыта, сообщение отправлено, возник сбой при закрытии соединения или еще что-то — в этом случае мы не теряем ни сообщение, ни данные.
  2. Возникла ошибка при сохранении данных, сообщение не отправилось — данные в нашей системе остаются согласованными.
  3. Данные сохранены, транзакция закрылась, сообщение не отправилось, возник сбой, в нашей системе образуются несогласованные данные, и мы не сразу это поймём.
  4. Данные сохранены, сообщение отправлено, но потом мы закрываем транзакцию и возникает ошибка, сохранение в БД откатывается — опять несогласованные данные.

Чтобы избежать несогласованности данных при обработке и последующей отправке сообщений, есть несколько решений, и одно из них — паттерн Outbox.

Суть паттерна Outbox

Это элегантное, простое в понимании и одновременно громоздкое в реализации решение.

При обработке данных и сохранении/обновлении сущности в БД сервис или компонент одновременно с этим сохраняет запись события в таблицу outbox. Две эти записи происходят в рамках одной транзакции. Следующий шаг — отправка сообщения в Event Bus. Служба по расписанию или по реакции на изменения в БД отправляет сообщение.

Есть несколько моделей реализации служб отправки сообщения:

  1. Poll-модель — отдельный процесс по расписанию проверяет таблицу outbox и отсылает новые сообщения в Event Bus. Недостаток данного подхода — запаздывание отправки сообщения.
  2. Change Data Capture — определенный процесс слушает изменения в таблице outbox и при появлении новой записи тут же отправляет ее в Event Bus. Существует множество решений, которые могут реагировать на изменения в данных таблицы, можно реализовать, читая изменения в логе транзакций, либо использовать готовое решение, такое как Debezium. Из очевидных минусов — необходимо либо реализовывать самим, либо подключать еще одно стороннее решение.
Как организовать гарантированную отправку сообщений в хореографии — паттерн Outbox

Ограничения Outbox

Из самого определения паттерна вытекают и его ограничния:

  • Задержка доставки сообщения — даже при использовании CDC модели отправка сообщений происходит со значительной задержкой по сравнению с прямой отправкой.
  • Увеличение нагрузки на БД — помимо записи изменений в доменной логике требуется запись в таблицу outbox. Более того, после отправки также требуется запись в таблицу о том, что сообщение отправлено.
  • Сложность реализации и поддержки — помимо реализации отправки сообщений, стоит задуматься об отказоустойчивости самой службы отправки, при самостоятельной реализации необходимо учесть следующие нюансы: что делать, если отправка сообщений упадет с ошибкой? Что делать, если сообщение не может быть прочитано и/или отправлено (изменилась схема, битые данные и т. п.).
  • Проблема с порядком отправки сообщений — обе модели не гарантируют очередность отправки сообщений, чтобы организовать строгий порядок, требуются дополнительные манипуляции с кодом.
  • Возможная доставка дубликатов. Необходимо предусмотреть идемпотентность обрабатываемых сообщений.

Итог

Паттерн Outbox — одно из возможных и распространенных решений в Event Driven архитектурах. Данный подход обеспечивает атомарный подход в сохранении данных и отправке сообщений об изменении данных, что замечательно подходит для систем, в которых взаимодействие реализовано с использованием хореографии. Но техническая реализация требует дополнительных усилий.

Подпишись на мой канал в telegram

Начать дискуссию