Паттерн Distributed Saga

Паттерн Distributed Saga —  это паттерн управления сбоями, где каждое действие имеет компенсирующее действие для отката. Распределенные саги помогают обеспечить согласованность и правильность микросервисов.

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

Пример распределенной саги

Рассмотрим сагу «Забронировать поездку» на платформе бронирования путешествий, состоящую из следующих запросов:

  1. Plan meeting
  2. Book flight
  3. Book hotel
  4. Book transport

Представим, что приложение Book hotel не смог обработать запрос:

Распределенная сага это коллекция запросов выполненных следующем порядке:

  1. Plan meeting
  2. Book flight
  3. Book hotel

Каждый запрос имеет компенсационный запрос (при возникновении проблемы), того порядок следующий:

  1. Cancel Book hotel
  2. Cancel Book flight
  3. Cancel Plan meeting (семантическая отмена запроса)

Т.е. Cancel Book hotel отменяет Book flight, Cancel Book flight отменяет Plan meeting и так далее.

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

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

Гарантия распределенной саги

Удивительно, но распределенная сага должна гарантировать один из следующих двух результатов:

  1. либо успешно выполнены все запросы в саге
  2. либо выполнена часть запросов + выполнены все компенсирующие запросы

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

Саги как конечные автоматы

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

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

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

Готовые решения

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

Существует семь типов состояний, которые вы можете использовать для создания конечного автомата. Task могут использоваться как запросы и запросы компенсации, а  Choice и  Parallel используется для потока управления.

Маленький итог

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

Внутри приложения

Давайте рассмотрим работу приложения на примере сервиса Order, которое использует подход называемый шаблоном «Отслеживание транзакционного журнала (transaction log tailing)». Принцип работы этого подхода:

1. Приложение принимает запрос, валидирирует его и сохраняет в базу данных в рамках транзакции. Каждое зафиксированное обновление (добавление, изменение, удаление - все перечисленное или что-то определенное), выполненное приложением, представлено в виде записи в журнале транзакций БД. Вы можете прочитать этот журнал и опубликовать каждое изменение в качестве сообщения для брокера. 

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

EventStore вместо журнала транзакций

Вместо журнала транзакций Вы можете использовать таблицу Events, таким образом:

  1. вместо использования Журнала транзакций мы можем создать таблицу Events (EventStore/History), в которой сервис сохраняет события агрегатов
  2. вместо вычитывания из Журнала транзакций, Анализатор журнала событий будет вычитывать записи из таблицы Events

Координация саг

Давайте рассмотрим 2 вида работы с сагами: хореография и оркестрация

Хореография

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

Преимущества

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

Недостатки

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

Оркестрация

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

Преимущества

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

Недостатки

  • Дополнительная сложность проектирования требует реализации логики координации.
  • Есть дополнительная точка отказа, так как Orchestrator управляет полным рабочим процессом.

Источники: 1 - 2


11.09.2021 07:08