Базы данных
Распределённые транзакции: 2PC и альтернативы
Booking.com. Пользователь бронирует отель и авиабилет одновременно. Payment сервис списал деньги. Hotel сервис недоступен. Деньги ушли, отель не забронирован. Это не баг - это фундаментальная проблема распределённых транзакций. Решения существуют - от 2PC до Saga, каждое с ценой.
- Uber использует Cadence (предшественник Temporal) для Saga-orchestration поездок: charge, dispatch, trip, payout - каждый шаг с компенсацией. 100M+ workflow executions в день
- Google Spanner обслуживает Google Ads, Google F1 (YouTube), Google Cloud SQL - глобально consistent транзакции через TrueTime + Paxos. 99.999% availability
- Stripe использует idempotency keys + outbox pattern вместо distributed transactions - каждая операция идемпотентна, at-least-once delivery через Kafka
2PC: координация через две фазы
Two-Phase Commit (2PC) - протокол 1978 года, Jim Gray. Цель: атомарная запись в несколько баз данных. Либо все commit, либо все rollback. XA-стандарт (X/Open Distributed Transaction Processing) стандартизировал интерфейс. Java JTA реализует поверх XA.
Проблема 2PC: coordinator является single point of failure. Если coordinator падает после отправки PREPARE но до COMMIT - участники заблокированы indefinitely. Они залоггировали PREPARE (нельзя commit самостоятельно), ресурсы заморожены. Это называется in-doubt transaction. Промышленные СУБД хранят in-doubt transactions до прихода нового coordinator.
In-doubt transactions в PostgreSQL видны в pg_prepared_xacts. Они держат row locks - блокируют обычные транзакции. Если coordinator падёт навсегда, нужно ручное вмешательство DBA: COMMIT PREPARED или ROLLBACK PREPARED. Это один из главных аргументов против 2PC в microservices: operational nightmare при сбоях.
Что происходит если coordinator падает между фазой PREPARE и COMMIT?
3PC: попытка решить blocking проблему
Three-Phase Commit (3PC) добавляет промежуточную фазу PRE-COMMIT между PREPARE и COMMIT. Цель: устранить blocking failure mode 2PC. Если coordinator упал - участники могут самостоятельно принять решение на основе знания о состоянии других участников.
Проблема 3PC: неустойчив при сетевых партициях. Network partition в момент PreCommit: часть участников получила PreCommit, часть нет. Одна группа решает commit, другая abort. Violated atomicity! 3PC безопасен только в синхронной сети без partitions - нереалистичное предположение для распределённых систем.
Paxos Commit (Gray & Lamport, 2004) - формальное решение: вместо coordinator используется Paxos quorum. Каждая фаза голосования через Paxos. Если 'coordinator' упал - любой участник может инициировать Paxos round. Google Spanner использует именно этот подход через Paxos groups. Latency выше: 2-3 round trips вместо 2.
Почему 3PC не решает проблему 2PC при сетевых партициях?
Saga: eventual consistency вместо ACID
Saga Pattern (Garcia-Molina & Salem, 1987) - отказ от distributed ACID в пользу eventual consistency с компенсирующими транзакциями. Вместо одной атомарной транзакции - последовательность локальных транзакций, каждая с компенсационной транзакцией для отката.
Choreography vs Orchestration. Choreography: каждый сервис публикует событие, следующий реагирует (Kafka events). Нет центрального координатора. Сложно отследить flow. Orchestration: центральный Saga Orchestrator (отдельный сервис или Temporal Workflow) вызывает каждый шаг, обрабатывает ошибки. Проще наблюдать, проще debug.
Temporal.io - Saga orchestration platform. Workflows - это durable functions: при crash автоматически восстанавливаются с последнего checkpoint через event sourcing. Uber использует Temporal для 100M+ workflow executions в день. Cadence (предшественник Temporal) обрабатывает поездки Uber.
Главное отличие Saga от 2PC?
Google Spanner и Paxos Commit
Google Spanner (2012): первая система с external consistency в глобальном масштабе. TrueTime API - синхронизация через GPS и атомные часы с погрешностью < 7мс. Транзакции commit timestamp присваивается после ожидания 2*epsilon для гарантии ordering.
Spanner использует Paxos groups вместо 2PC coordinator. Каждый shard - Paxos group из 5 реплик. Транзакция через несколько shards: leader каждого shard участвует в 2PC-подобном протоколе, но failure coordinator (leader) прозрачно обрабатывается через Paxos leader election. Blocking period = Paxos election timeout (~100ms).
CockroachDB и YugabyteDB реализуют схожий подход без GPS. Вместо TrueTime - HLC (Hybrid Logical Clocks). Немного слабее гарантии (linearizability vs external consistency), но без специального железа. CockroachDB используется в DoorDash, Netflix для глобально распределённых транзакций.
Какую проблему 2PC решает Paxos Commit?
Выбор протокола: pragmatic guide
Выбор между 2PC, Saga и Paxos Commit определяется тремя факторами: consistency требования, latency бюджет, операционная сложность. Нет universal answer - только tradeoffs.
Практическое правило 2024: избегай 2PC в microservices. Saga (Choreography или Temporal) - для большинства inter-service транзакций. 2PC допустим внутри одного кластера PostgreSQL с pg_prepared_xacts (XA). Paxos/Raft-based (CockroachDB, Spanner) - если нужна global ACID и есть бюджет.
Outbox Pattern - надёжный способ интеграции Saga с event-driven: INSERT в orders таблицу + INSERT в outbox таблицу в одной локальной транзакции. Отдельный поллер читает outbox и публикует события. Guarantees at-least-once delivery без distributed transaction. Debezium (Kafka Connect) реализует это через CDC из outbox.
Распределённые транзакции можно реализовать надёжно через 2PC с хорошим мониторингом
2PC имеет фундаментальный blocking failure mode: coordinator crash = frozen participants до восстановления. Мониторинг помогает обнаружить, но не устраняет проблему
FLP impossibility (Fischer-Lynch-Paterson 1985) доказывает: в асинхронной сети с одним падающим процессом невозможен distributed consensus за конечное время. 2PC не является исключением. Paxos/Raft обходят это через вероятностные гарантии (quorum, timeouts). Saga обходит через relaxed consistency
Когда 2PC остаётся разумным выбором в 2024?
Связанные темы
Распределённые транзакции пересекают boundaries БД, messaging и consensus:
- Блокировки и дедлоки — Локальные блокировки - фундамент для distributed
- CAP-теорема — CAP определяет пространство возможных trade-offs
- Saga Pattern в messaging — Choreography через event-driven messaging
Ключевые идеи
- 2PC: coordinator = SPOF, blocking failure mode при crash. Работает внутри одного кластера
- 3PC: non-blocking при fail-stop, но уязвим к network partitions - практически не используется
- Saga: eventual consistency + compensating transactions. Choreography (events) или Orchestration (Temporal)
- Paxos Commit (Spanner, CockroachDB): ACID без blocking через Paxos leader election
Вопросы для размышления
- Как выбрать между Choreography Saga и Orchestration Saga для конкретного бизнес-процесса?
- Что такое compensation idempotency и почему это критично для правильной Saga реализации?
- Когда eventual consistency достаточна, а когда strong consistency обязательна - где провести границу?
Связанные уроки
- db-15-locks — Блокировки - основа distributed координации
- db-03-acid — ACID - цель распределённых транзакций
- db-04-cap — CAP определяет ограничения распределённых транзакций
- bt-18-saga — Saga pattern - основная альтернатива 2PC
- dist-07-transactions