Потоковая обработка
Saga Pattern
Uber в 2016 году переходил с монолита на микросервисы. Бронирование поездки - это транзакция: создать поездку, зарезервировать водителя, заблокировать оплату. В монолите - одна SQL транзакция. В микросервисах - три отдельные базы. 2PC не масштабировался под нагрузку Uber. Команда разработала собственную реализацию Saga на базе Kafka. Сегодня это стандартный подход для распределенных транзакций в индустрии.
- **Amazon Order Processing:** создание заказа проходит через saga - резервирование товара, обработка оплаты, создание shipment - каждый шаг независимый сервис с компенсацией
- **Temporal.io:** open-source workflow engine для saga/orchestration, используется в Stripe, Netflix, Doordash; абстрагирует retry, state persistence и timeouts
- **Axon Framework:** Java-based CQRS/ES framework со встроенной поддержкой Saga; используется в banking системах где каждая бизнес-операция требует audit trail
Choreography-based Saga
Проблема: заказ создан в Order Service, оплата прошла в Payment Service, но склад не смог зарезервировать товар. Нужно откатить оплату. Но нет распределенной транзакции - каждый сервис имеет свою базу данных. Saga решает это через последовательность локальных транзакций с компенсациями. В хореографии нет дирижера: каждый сервис реагирует на события и сам публикует следующее.
Choreography saga: слабая связность, нет единой точки отказа, но сложно отследить общий flow. Идеально для простых, линейных сценариев с 2-3 шагами. Каждый сервис: слушает события -> выполняет локальную транзакцию -> публикует событие успеха или неудачи. Transactional Outbox: событие публикуется атомарно с локальной транзакцией - через таблицу в той же БД.
В choreography saga Payment Service не получил событие OrderCreated из-за сбоя Kafka. Что произойдет с заказом?
Orchestration-based Saga
Оркестрация решает главную слабость хореографии - невидимость общего flow. Saga orchestrator - это специальный объект, который знает весь сценарий: шаг 1 - оплата, шаг 2 - резервирование, шаг 3 - подтверждение. При сбое оркестратор знает какие компенсации запустить и в каком порядке. Цена: оркестратор становится центральной точкой знания о процессе - и потенциально точкой отказа.
Saga State Machine: каждая запущенная saga имеет состояние (pending, compensating, completed, failed) и текущий шаг. Persistence: состояние сохраняется в БД - при перезапуске оркестратор продолжает с того же места. Temporal.io - современный фреймворк для workflow/saga с автоматическим recovery. AWS Step Functions - managed orchestration для AWS-экосистемы.
Почему состояние Saga Orchestrator нужно сохранять в базе данных, а не только в памяти?
Компенсирующие транзакции
Компенсирующая транзакция - это не откат. Откат стирает изменения. Компенсация создает новые изменения, отменяющие эффект предыдущих. Оплата прошла и зафиксирована в истории. Компенсация создает возврат - новую запись в истории. Не все операции компенсируемы: отправленное email уже прочитано. Поэтому saga должна понимать, какие шаги reversible, а какие - pivot points, точки невозврата.
Типы транзакций в saga: Compensatable (можно компенсировать), Pivot (точка невозврата - после неё компенсация невозможна), Retriable (гарантированно выполнится при повторе). Паттерн: compensatable -> compensatable -> pivot -> retriable -> retriable. После pivot - только вперед. Идемпотентность компенсаций: повторный вызов refund не должен делать двойной возврат.
Заказ в saga прошел pivot point (списание денег). Шаг создания shipment упал. Что должна делать saga?
Saga vs 2PC: выбор подхода
До Saga паттерна распределенные транзакции решались через 2PC (Two-Phase Commit). Координатор спрашивал всех участников готов?, затем всем одновременно commit! Проблема: если участник подтвердил готовность, но упал до commit - неопределенность. Если координатор упал после prepare - все участники заблокированы. 2PC блокирует ресурсы, плохо масштабируется, чувствителен к сетевым разделениям. Saga - асинхронный, не блокирующий альтернатива.
2PC vs Saga: 2PC - synchronous, blocking, ACID-compliant; Saga - asynchronous, non-blocking, eventual consistency. 2PC подходит для небольшого числа участников в одном датацентре (PostgreSQL XA). Saga подходит для микросервисов с отдельными базами данных через сеть. Outbox Pattern + Kafka = надежная доставка без 2PC. BASE (Basically Available, Soft state, Eventually consistent) vs ACID.
Saga обеспечивает такую же ACID-гарантию как распределенная транзакция
Saga обеспечивает eventual consistency, но не изолированность (I в ACID); промежуточные состояния видны другим участникам
Между шагами saga данные находятся в частично обновленном состоянии - другие saga могут читать эти промежуточные данные. Это ACD-транзакции (без Isolation). Для критичных финансовых сценариев нужны дополнительные паттерны: semantic lock, commutative updates, pessimistic view.
Банк переводит деньги между счетами в двух разных микросервисах. Почему 2PC - плохой выбор?
Ключевые идеи
- **Choreography vs Orchestration:** хореография децентрализована и проста для 2-3 шагов; оркестрация дает видимый flow и нужна для сложных сценариев
- **Компенсация не равна откату:** компенсация создает новые бизнес-записи (возврат платежа), откат стирает изменения; не все шаги компенсируемы
- **Pivot point:** после точки невозврата - только retriable шаги; компенсация невозможна или бессмысленна
- **Saga vs 2PC:** saga асинхронна и не блокирует ресурсы; 2PC уязвима к сетевым разделениям в распределенной среде
Связанные темы
Saga Pattern решает проблему транзакций в архитектурах, где CQRS и Event Sourcing уже применяются:
- CQRS — Saga orchestrator использует Command (write side CQRS) для управления шагами
- Event Streaming (Kafka) — Choreography saga использует Kafka для асинхронной координации между сервисами
Вопросы для размышления
- Если компенсирующая транзакция сама падает (например, внешний payment gateway недоступен) - что должна делать saga? Как долго пытаться?
- Как тестировать saga в unit-тестах? Какие сценарии сбоев критично проверять?
- В каких случаях choreography предпочтительнее orchestration, несмотря на сложность отслеживания flow?