Потоковая обработка

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?

Связанные уроки

  • dist-07-2pc
Saga Pattern

0

1

Войти