Ответ
Паттерн Saga — это механизм управления распределенными транзакциями, который обеспечивает целостность данных в микросервисной архитектуре без использования блокирующих двухфазных коммитов (2PC).
Основная идея — разбить глобальную транзакцию на последовательность локальных транзакций, выполняемых в каждом сервисе. Если какой-либо шаг завершается неудачей, Saga запускает компенсирующие транзакции, которые отменяют результаты предыдущих успешных шагов.
Способы реализации Saga:
Choreography (Хореография):
- Нет центрального координатора.
- Сервисы общаются друг с другом через асинхронные события (events).
- Каждый сервис подписывается на события других сервисов и выполняет свою часть работы, после чего публикует собственное событие.
- Плюсы: Слабая связанность (loosely coupled).
- Минусы: Сложно отслеживать состояние всей транзакции, риск циклических зависимостей.
Orchestration (Оркестрация):
- Есть центральный сервис-оркестратор, который управляет всем процессом.
- Оркестратор вызывает сервисы в нужной последовательности и отвечает за запуск компенсирующих транзакций в случае сбоя.
- Плюсы: Централизованная логика, легко отслеживать состояние и добавлять новые шаги.
- Минусы: Оркестратор может стать узким местом и точкой отказа.
Пример псевдокода для Оркестрации:
// OrderSagaOrchestrator управляет процессом создания заказа
func OrderSagaOrchestrator(orderData Order) error {
// Шаг 1: Создать заказ
if err := orderService.CreateOrder(orderData); err != nil {
return err // Первый шаг не требует компенсации
}
// Шаг 2: Зарезервировать товары на складе
if err := inventoryService.ReserveInventory(orderData.Items); err != nil {
// Компенсация для шага 1
orderService.CancelOrder(orderData.ID)
return err
}
// Шаг 3: Обработать платеж
if err := paymentService.ProcessPayment(orderData.Amount); err != nil {
// Компенсация для шага 2
inventoryService.ReleaseInventory(orderData.Items)
// Компенсация для шага 1
orderService.CancelOrder(orderData.ID)
return err
}
return nil // Сага успешно завершена
}
Ключевые принципы реализации:
- Идемпотентность: Все операции (как прямые, так и компенсирующие) должны быть идемпотентными, чтобы повторный вызов не приводил к ошибкам или дублированию данных.
- Надежность компенсаций: Компенсирующие транзакции не должны завершаться сбоем. Если это возможно, они должны быть атомарными и надежными.
- Сохранение состояния: Оркестратор должен персистентно сохранять состояние саги, чтобы восстановить процесс после сбоя.