Паттерн: Сага

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

Например: давайте представим, что мы разрабатываем интернет магазин, где у клиента есть кредитный лимит. Приложение должно гарантировать, что новый заказ не превышает кредитный лимит клиента. Так как Заказы и Клиенты — различные базы данных, то приложение не может использовать локальные ACID транзакции.

Проблема

Как обеспечить согласованность данных между сервисами?

Решение

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

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

Существует два способа координации саг:

  • Хореография (Choreography) — каждая транзакция публикует события, которые запускают транзакции в других сервисах.
  • Оркестровка (Orchestration) — оркестратор говорит участникам, какие транзакции должны быть запущены.
Пример: сага, основанная на хореографии

В интернет магазине с использованием саги, основанной на хореографии, создание заказа будет включать следующие шаги:

  1. Order Service (Сервис Заказа) создает Order (Заказ) в статусе pending (в ожидании) и публикует событие OrderCreated (ЗаказСоздан)
  2. Customer Service (Сервис Клиента) получает событие и пытается зарезервировать кредит для заказа. После чего публикует одно из двух событий: CreditReserved (КредитЗарезервирован) или CreditLimitExceeded (КредитныйЛимитПревышен)
  3. Order Service (Сервис Заказа) получает событие и изменяет состояние заказа в approved (подтвержден) или cancelled (отменен)
Пример: сага, основанная на оркестровке

В интернет магазине с использованием саги, основанной на оркестровке, создание заказа будет включать следующие шаги:

  1. Order Service (Сервис Заказа) создает Order (Заказ) в статусе pending (в ожидании) и создает CreateOrderSaga (СагаСозданияЗаказа)
  2. CreateOrderSaga (СагаСозданияЗаказа) отправляет команду ReserveCredit (ЗарезервироватьКредит) в Customer Service (Сервис Клиента)
  3. Customer Service (Сервис Клиента) пытается зарезервировать кредит для заказа и отправляет назад ответ
  4. CreateOrderSaga (СагаСозданияЗаказа) получает ответ и отправляет ApproveOrder (ПодтвердитьЗаказ) or RejectOrder (ОтменитьЗаказ) команду в Order Service (Сервис Заказа)
  5. Order Service (Сервис Заказа) изменяет состояние заказа в approved (подтвержден) или cancelled (отменен)
Сага имеет следующие преимущества
  • Позволяет приложению поддерживать согласованность данных между сервисами без использования распределенных транзакций.
Сага имеет следующие недостатки
  • Модель программирования становится более сложной. Например, разработчики должны проектировать компенсирующие транзакции, которые отменяют изменения, сделанные ранее в саге.