Вопросы о паттерне встречаются на собеседованиях, и часто они не конкретные: "Как обеспечить консистентность данных в распределенной системе?" или "Как обойти отсутствие транзакций в распределенной системе?".
Иногда вас прямо попросят рассказать о паттерне SAGA. И это правильный ход мыслей. Не стоит рассказывать о распределенных транзакциях БД, так как это дорогой инструмент из-за необходимости подтверждения транзакции на всех узлах-участниках.
📚 Суть паттерна SAGA
SAGA - это архитектурный паттерн, который используется для обеспечения консистентности данных в распределенной системе за счет локальных и компенсирующих транзакций. Очень грубо можно назвать SAGA распределенной транзакцией. Но она построена не на транзакционности БД, а на обмене сообщениями между сервисами.
SAGA включает последовательность локальных бизнес-операций в сервисе, которые выполняются транзакционно и публикуют события в брокер сообщений. Другие сервисы обрабатывают события и запускают новые последовательности локальных транзакций, пока SAGA не выполнится успешно. Если одна из бизнес-операций выполняется неуспешно, то сервис публикует компенсационное событие, которое обрабатывается участниками SAGA и приводит к запуску компенсирующих транзакций, которые возвращают состояние системы в первоначальное состояние.
SAGA можно реализовать двумя способами: оркестрация и хореография.
🎭 Оркестрация
При оркестрации сервис-оркестратор сообщает всем участникам SAGA, какие локальные и компенсирующие транзакции выполнять. Бизнес-логика по управлению последовательностью действий в SAGA находится в сервисе-оркестраторе. Он публикует события, запускающие выполнение логики в других сервисах, а также обрабатывает ответные события, чтобы запустить следующий шаг в цепочке или опубликовать компенсирующие события.
A <-- events --> Orchestrator <-- events --> B
/
C <-- events -->
При таком подходе проще разбирать сбои и поддерживать бизнес-логику SAGA, так как она находится в одном месте. Но появляется единая точка отказа.
Откат SAGA выполняется через оркестратор. Один из сервисов отправляет неуспешное событие, реагируя на которое оркестратор публикует компенсационные события предыдущих выполненных шагов.
💃 Хореография
При хореографии сервис-оркестратор отсутствует. Сервисы "знают", куда и какие события отправлять и обрабатывать. После выполнения локальной транзакции сервис отправляет событие напрямую в целевой сервис, минуя оркестратор.
A <-- events --> B <-- events --> C
Подход позволяет избавиться от единой точки отказа, но усложняет поддержку. Теперь бизнес-логика выполнения SAGA размазана по нескольким сервисам.
Откат SAGA обычно выполняется по цепочке: если локальные транзакции сервиса C выполнены неуспешно, то он публикует компенсационное событие для сервиса B, B — для A.
Сервис C может опубликовать компенсационные события и для сервиса A. Но это усложнит логику обработки ошибок в неуспешных локальных транзакциях сервиса C, так как ему нужно будет знать о всех участниках SAGA. Это существенно усложнит разработку и поддержку SAGA, если сервисов в цепочке больше 3.
📋 Выводы
- ✅ SAGA позволяет поддерживать консистентность данных между несколькими сервисами без использования распределенных транзакций.
- ❌ SAGA не поддерживает автоматический откат и требует от разработчика реализации компенсирующих транзакций. Это усложняет разработку и поддержку.
Оркестрация обеспечивает централизованное управление SAGA и упрощает разработку. В то время как хореография позволяет исключить единую точку отказа. С учетом современных подходов к горизонтальному масштабированию сервисов, когда каждый экземпляр запущен в несколько копий, этой проблемой можно пренебречь в пользу упрощения разработки и поддержки в оркестрации.
Теперь ты знаешь, что такое SAGA, и успешно расскажешь о ней на собеседовании!
#техничка #backend