Короткий ответ
2PC даёт строгую атомарность между несколькими БД за счёт координатора, который синхронно удерживает блокировки на всех участниках до commit, но плохо масштабируется и уязвим к недоступности координатора/участника; Saga разбивает операцию на последовательность локальных транзакций с компенсирующими действиями на случай неудачи, что масштабируется лучше, но требует продумывания каждой компенсации и временного окна промежуточной неконсистентности.
Как это работает подробнее
2PC проходит через фазу подготовки (каждый участник резервирует изменения и сообщает «готов») и фазу коммита — пока не пройдена вторая фаза, ресурсы у всех участников заблокированы; Saga выполняет шаги последовательно как независимые локальные транзакции, и при ошибке запускает заранее определённые компенсирующие операции для уже выполненных шагов.
Сравнение
- Компромисс. Выбор зависит от требуемой строгости согласованности (мгновенная vs eventual), числа и разнородности участников, частоты операций и готовности команды поддерживать компенсирующую логику; для низкочастотных критичных операций в контролируемой инфраструктуре 2PC может быть оправдан, для высоконагруженной распределённой системы почти всегда предпочтительнее Saga с явным учётом окна неконсистентности.
Пример кода
Сценарий: заказ = резерв товара (Inventory service) + списание оплаты (Payment service).
Saga:
1) OrderService: создать заказ в статусе "pending".
2) InventoryService: зарезервировать товар (локальная транзакция) -> событие "reserved".
3) PaymentService: списать оплату (локальная транзакция).
- Если оплата не прошла -> компенсация: InventoryService отменяет резерв -> "reservation_cancelled".
4) OrderService: перевести заказ в "confirmed" или "cancelled" по итогам шагов.
Риск: между шагом 2 и 3 товар зарезервирован, но заказ ещё не оплачен — нужно явно решить,
сколько времени держать резерв и что считать таймаутом для запуска компенсации.Что использовать на практике
- Практика. 2PC применим, когда все участники поддерживают протокол и объём операций не слишком высок; Saga — типичный выбор для микросервисной архитектуры с разными технологиями хранения и высокой частотой операций, но требует идемпотентных шагов и компенсаций.
Подводные камни
- Ошибка. Реализуют Saga без идемпотентности шагов, из-за чего повторная доставка сообщения приводит к двойному списанию/резервированию; не предусматривают, что компенсирующая операция сама может завершиться с ошибкой, оставляя систему в неопределённом состоянии без алертинга.