Распределённые системы

Распределённые транзакции

Цели урока

  • Понимать проблему атомарности поперёк независимых сервисов и 4 сценария частичного сбоя
  • Знать протокол 2PC, его гарантии и ключевые ограничения (blocking, coordinator failure)
  • Применять Saga Pattern с компенсирующими транзакциями для eventual consistency
  • Выбирать между Orchestration и Choreography исходя из сложности flow и требований

Предварительные знания

  • ACID-транзакции в одной БД (atomicity, isolation, durability)
  • Базовое понимание микросервисной архитектуры
  • Понятие WAL (Write-Ahead Log) и crash recovery
  • Eventual consistency vs strong consistency

eBay в 2004 году терял 1.5 миллиарда долларов в год на частичных сбоях между сервисами - платёж прошёл, заказ не создан. Это не баг в коде, это фундаментальная проблема распределённых систем без правильного протокола.

  • **Uber Payments** - Saga с Orchestration для ride payment: 5 шагов (auth, hold, trip, release, charge), compensate при любом сбое
  • **Amazon Order Pipeline** - Choreography через EventBridge: 100+ шагов, каждый сервис автономен, нет единого coordinator-а
  • **Stripe Payments** - 2PC для internal DB + idempotency keys для API - клиент может безопасно ретраить любой запрос
  • **Google Spanner** - distributed transactions через 2PC поверх Paxos: coordinator - лидер группы Paxos
  • **Airbnb Booking** - Saga + Outbox Pattern: событие пишется в ту же БД что и бизнес-данные - атомарность через одну транзакцию

2PC и история распределённых транзакций

Two-Phase Commit изобрёл Джим Грей в конце 1970-х в IBM Research. В 1979 году он опубликовал формальное описание в статье 'Notes on Database Operating Systems'. Грей также ввёл понятия ACID, WAL и concurrency control - фундамент всех современных БД. Turing Award 1998 году. В 2007 году Грей исчез в море на своей яхте - тело так и не нашли.

Проблема атомарности поперёк узлов

**2004 год, eBay. Платёжная система отправила списание на PayPal - подтверждение пришло. Но запись о заказе в БД eBay не сохранилась: сервер упал через 80 мс. Покупатель заплатил, товар не зарезервирован. За год такие частичные сбои стоили компании 1.5 миллиарда долларов потерь и возвратов.** Это и есть проблема распределённых транзакций: операция затрагивает несколько узлов, а ACID гарантии действуют только в рамках одного.

**Три сценария частичного сбоя:** 1. первый узел выполнил операцию, второй упал - данные потеряны; (2) оба выполнили, но подтверждение потеряно в сети - операция дублируется при retry; (3) первый выполнил, второй отказал по бизнес-логике - нужен откат первого. Каждый сценарий требует отдельной стратегии.

СценарийПроблемаНужна стратегия
Узел B упал после успеха AДеньги списаны, не зачислены2PC rollback или компенсация
Ответ A потерялся в сетиКлиент делает retry - двойное списаниеIdempotency key
B отказал по бизнес-логикеA выполнено, B нет - нужен откат ASaga compensating transaction
Coordinator упал в серединеУчастники заблокированы в PREPARED2PC timeout + 3PC или Saga

Транзакция в микросервисах работает так же, как BEGIN/COMMIT в PostgreSQL

Каждый сервис фиксирует свою локальную транзакцию независимо - нет общего ROLLBACK поперёк границ

PostgreSQL ACID - это один process, один WAL, один lock manager. В распределённой системе у каждого сервиса своя БД, своя изоляция, свой момент commit. Координировать их можно только через протоколы (2PC) или паттерны (Saga) - и ни тот ни другой не даёт полного ACID.

Клиент вызвал перевод денег: сервис A (списание) ответил OK, сервис B (зачисление) упал. Какое состояние системы?

Two-Phase Commit (2PC)

**Two-Phase Commit** - классический протокол для атомарных распределённых транзакций. Один узел становится Coordinator, остальные - Participants. Протокол строится на блокировке ресурсов до момента финального решения: либо все коммитят, либо все откатывают.

Проблема 2PCОписаниеПоследствие
BlockingРесурсы залочены от Phase 1 до Phase 2При высоком RPS - деградация throughput на 5-10x
Coordinator failureУчастники зависают в PREPARED бесконечноDeadlock до восстановления coordinator-а
Network partitionCoordinator не получает ответы от части участниковTimeout - принудительный ABORT даже если все готовы
Не масштабируетсяSynchronous wait всех участниковLatency = max(latency всех узлов)

**2PC - blocking protocol.** Если Coordinator упал после Phase 1 (все ответили YES) но до Phase 2 - участники держат локи неопределённо долго. Эту проблему частично решает Three-Phase Commit (3PC), но у него свои trade-offs. В production с микросервисами 2PC практически не применяется.

Coordinator в 2PC записал COMMIT в свой WAL, но упал до отправки COMMIT участникам. Что произойдёт?

Saga Pattern: цепочка компенсаций

**Uber, 2016 год. При запуске микросервисной архитектуры столкнулись с проблемой: 2PC не работает поперёк 50+ независимых сервисов (trips, payments, drivers, surge, promotions). Решение - Saga Pattern: длинная транзакция разбивается на цепочку локальных транзакций. Каждая шаг имеет компенсирующее действие (compensating transaction). Если шаг N упал - выполняются компенсации шагов N-1, N-2, ... в обратном порядке.**

**Ключевое отличие компенсации от отката:** обычный ROLLBACK стирает как будто операции не было. Компенсирующая транзакция - это новая бизнес-операция (возврат платежа, снятие резерва). Она видна в логах, она может частично не работать, она должна быть idempotent. Это eventual consistency, а не ACID.

Saga гарантирует ACID так же как локальная транзакция

Saga даёт eventual consistency - между шагами система находится в промежуточном состоянии

После шага 1 (списание) и до шага 2 (зачисление) проходит реальное время - десятки мс. Другие клиенты могут видеть списанные деньги и незачисленный товар. Это называется ACI без D в терминах BASE (Basic Availability, Soft state, Eventual consistency). Для большинства бизнес-процессов это приемлемо.

В Saga шаги 1 и 2 выполнены успешно, шаг 3 упал. Что должно произойти?

Choreography vs Orchestration

**Saga реализуется двумя способами.** Orchestration: один центральный сервис (Orchestrator) вызывает все шаги по порядку и управляет компенсациями. Choreography: каждый сервис слушает события и реагирует самостоятельно - нет центрального координатора. Amazon Order Service, Uber Dispatch, Netflix Watch Party - все используют гибрид в зависимости от сложности flow.

ПодходКак работаетПлюсыМинусы
OrchestrationЦентральный сервис вызывает шаги и компенсацииFlow читается как код, легко debug, rollback явныйSingle point of failure, coupling через orchestrator
ChoreographyСервисы реагируют на события из очередиLoose coupling, нет SPOF, легко добавить шагFlow неявный, сложно debug, compensate надо продумывать

**Правило выбора:** если flow линейный и 3-5 шагов - Orchestration (проще debug). Если шагов 10+ или нужна максимальная автономность сервисов - Choreography. Uber использует Orchestration для критических финансовых flow (ride payment) и Choreography для аналитических pipeline.

СистемаПодходПочему
Uber PaymentsOrchestrationФинансовая атомарность, нужен явный audit trail
Amazon OrderChoreography100+ шагов, независимые команды, loose coupling
Netflix BillingOrchestrationCompliance требует предсказуемого rollback
Airbnb BookingSaga + OutboxOutbox pattern для надёжной публикации событий

Какой подход лучше для финансового процесса с 4 шагами, где важен чёткий audit log и предсказуемый rollback?

Вопросы для размышления

  • Банк реализует перевод между счетами через Saga (списание с одного счёта - зачисление на другой). Между шагами 1 и 2 проходит 200 мс. Какие проблемы могут возникнуть и как их решить?

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

  • ds-03-consensus — Atomic commit requires agreement across nodes
  • dist-07-2pc — 2PC is the standard distributed transaction commit protocol
  • dist-12-consistency — Transaction isolation level determines consistency guarantees
  • ds-11-distributed-locks — Pessimistic transactions use distributed locks
  • db-13-transactions
Распределённые транзакции

0

1

Войти