Ответ
Saga — это паттерн для управления долгоживущими бизнес-транзакциями в распределенных системах (микросервисах), где классические ACID-транзакции неприменимы. Saga разбивает транзакцию на последовательность локальных шагов, каждый из которых обновляет данные в одном сервисе и публикует событие для следующего шага. При сбое выполняются компенсирующие действия (Compensating Transactions) для отката предыдущих шагов.
Два основных стиля реализации:
-
Оркестрация (Orchestration): Центральный координатор (оркестратор) управляет потоком выполнения.
// Упрощенный пример оркестратора Saga public class OrderCreationSagaOrchestrator { public void execute(Order order) { try { inventoryService.reserveItems(order); // Шаг 1 paymentService.charge(order); // Шаг 2 shippingService.schedule(order); // Шаг 3 // Saga завершена успешно } catch (Exception e) { // Запуск компенсирующих действий paymentService.refund(order); inventoryService.releaseItems(order); // Saga завершена с ошибкой } } } -
Хореография (Choreography): Сервисы координируют работу через обмен событиями без центрального управляющего компонента.
Критически важные аспекты при реализации:
- Идемпотентность: Все шаги и компенсации должны быть идемпотентными для безопасного повтора.
- Наблюдаемость: Необходимо сквозное логирование (correlation ID) для отслеживания состояния Saga.
- Сложность отладки: Распределенный характер Saga усложняет отладку по сравнению с монолитной транзакцией.
Опыт применения: Использовал Saga с оркестрацией (на Spring State Machine) для реализации процесса оформления заказа в e-commerce, где необходимо согласованно обновить инвентарь, списать деньги и создать доставку.
Ответ 18+ 🔞
Ну вот, опять про эти ваши саги, блядь. Сидишь такой, думаешь — микросервисы, красота, независимость, масштабирование, ёпта! А потом бац — и надо заказ оформить, который в трёх разных конторах данные трогает. И тут тебе классические транзакции на базу данных, как манна небесная, уже не светят, потому что каждый сервис свою отдельную базу имеет, сука. И начинается этот цирк.
Saga — это, грубо говоря, такой костыль, но охуенно продуманный, для вот этих самых долгих, блядь, бизнес-процессов. Вместо того чтобы всё сделать разом и откатить разом (как в старые добрые ACID-времена), мы эту операцию на куски режем. Каждый кусок — это локальный шаг в одном сервисе. Сделал шаг — выпустил событие, чтобы следующий за тобой подхватил. А если где-то посередине пиздец случился, то надо откатывать всё, что уже наворотили. Но не через волшебный ROLLBACK, а вручную, сука, через компенсирующие транзакции. То есть для каждого шага пишешь ещё и обратную операцию, которая всё по-братски вернёт как было. Веселье, блядь, ещё то.
Как это, блядь, можно организовать? Да как обычно — или бардак, или диктатура.
-
Оркестрация (Orchestration). Это когда есть один главный по тарелочкам, оркестратор. Он, как мамка непутёвым детям, всем командует: ты сделай это, ты — то, а ты вообще стой, блядь, не двигайся. Все шаги идут строго по его указке. Если где-то сбой — он же и запускает откат по составленному им же плану.
// Вот смотри, типа как этот зануда-оркестратор может выглядеть public class OrderCreationSagaOrchestrator { public void execute(Order order) { try { inventoryService.reserveItems(order); // Шаг 1: резервируем товар paymentService.charge(order); // Шаг 2: списываем бабки shippingService.schedule(order); // Шаг 3: планируем доставку // Всё, сага успешно завершена, можно выдохнуть } catch (Exception e) { // А вот тут пиздец, чувак! Начинаем откат, как в боевике. paymentService.refund(order); // Компенсация: возвращаем бабки inventoryService.releaseItems(order); // Компенсация: разрезервируем товар // Всё, сага похерена, но система в консистентном состоянии. Вроде как. } } } -
Хореография (Choreography). А это уже анархия, блядь. Нет центральной власти. Каждый сервис, сделав своё дело, кричит в общую шину событий: «Эй, я тут товар зарезервировал!». Следующий сервис этот крик слышит, делает своё дело и кричит: «А я бабки списал!». И так по цепочке. Если кто-то нихуя не сделал и не прокричал — все остальные так и будут ждать, как идиоты. А для отката нужно, чтобы каждый сервис ещё и умел слушать события о пиздеце и запускать свою компенсацию. Бардак, но зато распределённый, ебать его в сраку.
А теперь, блядь, самое важное, что все просрать могут:
- Идемпотентность — это святое. Твои шаги и компенсации могут вызвать по три раза из-за таймаутов, повторов и прочей сетевой хуйни. Они должны быть готовы к этому. Вызвали
charge(order)дважды? Должно быть всё равно, что один раз. Иначе на клиенте двойное списание, а он тебе потом ебальник набьёт. - Наблюдаемость. Ты должен всегда знать, в каком состоянии твоя сага, а то она где-то посередине зависнет, и хуй поймёшь — деньги списались или нет, товар зарезервирован или уже нет. Correlation ID — твой лучший друг, прокидывай его везде и логируй по нему.
- Сложность отладки. Отлаживать такую распределённую хуйню — это тот ещё пиздец. В монолите ты в дебаггере прошёлся по стеку и всё понял. А тут у тебя логи по десяти сервисам размазаны, события где-то потерялись... Ёперный театр, короче.
Опыт применения: Я эту банду настраивал в одном интернет-магазине, на Spring State Machine, по схеме с оркестратором. Ну, потому что хореография — это для мазохистов, когда сервисов три и все написаны тобой же. А тут процесс оформления заказа: резерв на складе, оплата, создание доставки. Оркестратор рулил этим процессом как царь. Работало, но, блядь, сколько крови это выпило на этапе отладки и обеспечения той самой идемпотентности... Волосы дыбом вставали, ей-богу.