GH GambleHub

Сага-патерн і розподілені транзакції

Сага-патерн і розподілені транзакції

1) Навіщо потрібні саги

Класичний 2PC (двофазна фіксація) погано масштабується, складний під відмовами і блокує ресурси. Сага розбиває загальний бізнес-процес на послідовність локальних транзакцій (кроків), кожна з яких коммітиться незалежно. При збої наступні кроки скасовуються, а вже виконані - компенсуються зворотними операціями.
Результат: керована eventual consistency без глобального блокування, висока живучість і чіткий протокол відновлення.

2) Базові моделі

2. 1 Оркестрація

Виділений координатор саги керує кроками: посилає команди, чекає відповіді/події, ініціює компенсації.
Плюси: централізований контроль, проста спостережуваність, явні дедлайни. Мінуси: додатковий компонент.

2. 2 Хореографія

Немає координатора; сервіси реагують на події один одного («OrderPlaced» → «PaymentCaptured» → «InventoryReserved»...).
Плюси: Слабка зв'язність. Мінуси: складніше простежувати, ризик «танцю смерті» без чітких правил.

2. 3 TCC (Try-Confirm/Cancel)

Варіант з «заморожуванням» ресурсів:

1. Try - підготовка/резерв,

2. Confirm - фіксація,

3. Cancel - відкат.

Гарантії вище, але складніше контракти і таймаути резервів.

3) Контракти кроків і компенсації

Кожен крок = локальна транзакція + компенсація (ідемпотентна, допускає повтор).
Компенсація не зобов'язана повністю «повернути мир» - достатньо доменної еквівалентності (наприклад, «виплата повернення» замість «видалити платіж»).
Визначте інваріанти: для грошей - баланс не йде в мінус; для замовлень - немає «завислих» статусів.
Вводьте дедлайни/TTL резервів і «garbage collector» для прострочених спроб.

4) Узгодженість і семантики доставки

Доставка повідомлень: at-least-once (дефолт) → всі операції повинні бути ідемпотентними.
Порядок: важливий за кореляційним ключем (наприклад,'order _ id','player _ id').
Exactly-once - не мета саги; домагаємося ефективної рівно-однократності через ідемпотентні ключі, outbox/inbox і коректне комітування.

5) Стан саги та її лог

Що зберігати:
  • 'saga _ id','correlation _ id', поточний статус (Running/Completed/Compensating/Compensated/Failed),
  • крок і його змінні (IDs платежів/резервів),
  • історію (журнал) подій/рішень, таймстемпи, дедлайни, число ретраїв.
Де зберігати:
  • Окремий Saga Store (таблиця/документ), доступний координатору.
  • Для хореографії - локальні «агенти» саги, що публікують події статусу в загальний топік.

6) Патерни надійної публікації: outbox/inbox

Outbox: крок комітить зміни і записує подію/команду в таблицю outbox в одній транзакції; воркер публікує в шину.
Inbox: споживач веде таблицю оброблених'message _ id'→ дедуп + ідемпотентність.
Після успішного побічного ефекту коммітимо offset/ACK (Kafka/RabbitMQ) - не раніше.

7) Проектування кроків саги

7. 1 Приклад (покупка в iGaming/e-commerce)

1. PlaceOrder → статус'PENDING'.
2. AuthorizePayment (Try) → `payment_hold_id`.
3. ReserveInventory → `reservation_id`.
4. CapturePayment (Confirm).
5. FinalizeOrder → `COMPLETED`.

Компенсації:
  • якщо (3) провалився →'CancelPaymentHold';
  • якщо (4) провалився після (3) → «ReleaseInventory»;
  • якщо (5) провалився → «RefundPayment» і «ReleaseInventory».

7. 2 Дедлайни/ретраї

Максимум N ретраїв з експоненціальною затримкою + джиттер.
Після перевищення - перехід в'Compensating'.
Зберігайте next_attempt_at і deadline_at для кожного кроку.

8) Оркестратор vs платформа

Варіанти:
  • Легкий домашній оркестратор (мікросервіс + таблиця Saga).
  • Платформи: Temporal/Cadence, Camunda, Netflix Conductor, Zeebe - дають таймери, ретраї, довгоживучі воркфлоу, видимість і веб-консоль.
  • Для хореографії використовуйте каталог подій і сувору угоду про статуси/ключі.

9) Протоколи інтеграції

9. 1 Асинхронно (Kafka/RabbitMQ)

Команди: `payments. authorize. v1`, `inventory. reserve. v1`.
Події: `payments. authorized. v1`, `inventory. reserved. v1`, `payments. captured. v1`, `payments. refunded. v1`.
Ключ партії ='order _ id '/' player _ id'для порядку.

9. 2 Синхронно (HTTP/gRPC) всередині кроку

Допустимо для «коротких» кроків, але завжди з таймаутами/ретраями/ідемпотентністю і fallback в асинхронну компенсацію.

10) Ідемпотентність і ключі

У запитах команд і компенсацій передавайте'idempotency _ key'.
Побічні ефекти (запис в БД/списання) виконуються умовно: «виконати якщо ще не бачили'idempotency _ key'».
Компенсації теж ідемпотентні: повтор'RefundPayment (id = X)'безпечний.

11) Обробка помилок

Класи:
  • Transient (мережі/таймаути) → ретраї/backoff.
  • Business (недостатньо коштів, ліміти) → негайна компенсація/альтернативний шлях.
  • Irrecoverable (порушення інваріанта) → ручне втручання, «ручна» компенсація.
  • Вибудовуйте матрицю рішень: тип помилки → дію (retry/compensate/escalate).

12) Спостережуваність і SLO саг

SLI/SLO:
  • End-to-end latency саги (p50/p95/p99).
  • Success rate (частка завершених без компенсацій).
  • Mean time to compensate и compensation rate.
  • Orphaned sagas (висять) і час до GC.
  • Трасування: 'trace _ id '/' saga _ id'як span link між кроками; метрики burn-rate для бюджетів помилок.

Логи: кожна зміна статусу саги = структурований запис з причиною.

13) Приклади (псевдокод)

13. 1 Оркестратор (ідея)

python def handle(OrderPlaced e):
saga = Saga. start(e. order_id)
saga. run(step=authorize_payment, compensate=cancel_payment)
saga. run(step=reserve_inventory, compensate=release_inventory)
saga. run(step=capture_payment, compensate=refund_payment)
saga. run(step=finalize_order, compensate=refund_and_release)
saga. complete()

def run(step, compensate):
try:
step () # local transaction + outbox except Transient:
schedule_retry()
except Business as err:
start_compensation(err)

13. 2 Outbox (ідея таблиці)


outbox(id PK, aggregate_id, event_type, payload, created_at, sent_at NULL)
inbox(message_id PK, processed_at, status)
saga(order_id PK, state, step, next_attempt_at, deadline_at, context JSONB)
saga_log(id PK, order_id, time, event, details)

13. 3 Хореографія (ідеї тем)

`orders. placed'→ споживачі: `payments. authorize`, `inventory. reserve`

`payments. authorized` + `inventory. reserved` → `orders. try_finalize`

Будь-яка відмова →'orders. compensate'→ ініціюються'payments. cancel/refund`, `inventory. release`.

14) Порівняння з 2PC і ES

2PC: сильна узгодженість, але блокування, вузькі місця, «мідні труби».
Сага: eventual consistency, потрібна дисципліна компенсацій і телеметрії.
Event Sourcing: зберігає події як джерело істини; саги на ньому природні, але додають складність міграцій/снапшотів.

15) Безпека та комплаєнс

Сек'юрність транспорту (TLS/mTLS), ACL per topic/queue.
У подіях - мінімум PII, шифрування чутливих полів, токенізація.
Аудит доступу до саг і журналів компенсацій.
SLA з зовнішніми провайдерами (платежі/доставка) = параметри дедлайнів і лімітів ретраїв.

16) Чек-лист впровадження (0-45 днів)

0-10 днів

Виділіть процеси-кандидати (мультисервісні, з компенсацією).
Виберіть модель (оркестрація/хореографія/ТСС) і кореляційний ключ.
Опишіть кроки/компенсації, інваріанти та дедлайни. Підніміть таблиці «saga», «outbox», «inbox».

11-25 днів

Увімкніть outbox/inbox, ідемпотентність і ретраї з backoff.
Деплойте перші саги; додайте дашборди SLI/SLO і трасування.
Напишіть runbook компенсацій (в т.ч. ручних) і ескалацій.

26-45 днів

Автоматизуйте GC «висять» саг, періодичні перезапуски/продовження по дедлайну.
Проведіть game-day: відмова кроку, перевищення дедлайну, недоступність брокера.
Стандартизуйте контракти подій (версії, сумісність), заведіть «каталог саг».

17) Анти-патерни

«Компенсація = delete з БД» замість доменно коректної зворотної дії.
Немає outbox/inbox → втрата подій/подвійні ефекти.
Ретраї без джиттера → само-DDoS залежностей.
Очікування сильної узгодженості на читанні без «йде обробка»....
Один гігантський оркестратор на всі → моноліт управління.
Тотальна хореографія без видимості і SLA → некерований танець.
Ігнорування дедлайнів → вічні резерви/холди.

18) Метрики зрілості

≥ 90% критичних процесів покриті сагами/компенсаціями і мають описані інваріанти.
Outbox/inbox інтегровані для всіх продьюсерів/консьюмерів Tier-0/1.
SLO: p95 end-to-end саги в нормі, success rate стабільний, orphaned <цільового.
Прозора трасування і дашборди «по кроках», burn-rate алерти.
Щоквартальний game-day і перевірка ручних runbook-компенсацій.

19) Висновок

Сага - це практичний контракт узгодженості для розподілених систем: чіткі кроки і зворотні дії, дисципліна публікації (outbox/inbox), дедлайни і ретраї, спостережуваність і процеси компенсації. Виберіть модель (оркестрація/хореографія/ТСС), зафіксуйте інваріанти і ключі, зробіть обробники ідемпотентними - і ваші мультисервісні бізнес-процеси стануть передбачуваними і стійкими без дорогого 2PC.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.