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

Тема дорожной карты · Backend разработчик

Паттерн Saga — это паттерн управления распределёнными транзакциями в микросервисных архитектурах, позволяющий поддерживать согласованность данных в нескольких сервисах без использования двухфазной фиксации (2PC), которая практически неприменима для независимых баз данных. Saga декомпозирует долго выполняющуюся бизнес-транзакцию (например, оформление заказа, охватывающего сервис инвентаря, платёжный сервис и сервис доставки) на последовательность локальных транзакций, каждая из которых публикует доменное событие в Kafka или RabbitMQ, инициирующее следующий шаг. Существует два стиля реализации: Choreography-based Saga, где каждый сервис автономно реагирует на события, и Orchestration-based Saga, где центральный сервис-оркестратор (нередко реализованный с помощью Axon Framework или Temporal) явно управляет каждым шагом и обрабатывает сбои. Компенсирующие транзакции — краеугольный камень паттерна Saga: при сбое любого шага уже завершённые шаги должны быть явно отменены (например, возврат платежа или восстановление остатка товара), что делает идемпотентность и дедупликацию событий критически важными требованиями для каждого участвующего сервиса. Паттерн Saga часто сочетается с CQRS и DDD, где каждый сервис владеет схемой PostgreSQL или MySQL и генерирует типизированные доменные события с использованием Protocol Buffers или JSON.

Как это работает

Saga и распределённые транзакции имеет варианты: монолит (один деплоябл, простой ops, тяжело масштабировать команды за ~30 инженеров), modular monolith (один деплоябл, внутренние границы модулей, масштабируется намного дальше, чем считают), микросервисы (много мелких сервисов, сложный ops, масштабирует команды). Паттерны: hexagonal / clean architecture (отделить домен от инфры), CQRS (раздельные read + write модели), event sourcing (state из event log), domain-driven design (моделируем бизнес). "Правильная" архитектура — простейшая, решающая текущие ограничения.

Когда применять

Каждый новый проект — modular monolith. Разделяйте на сервисы только когда (а) в команде > ~30 инженеров, (б) у одного компонента сильно другие требования к масштабу, (в) регуляторные границы требуют изоляции. "Архитектура" — это в основном про что вы можете дёшево менять потом; принимайте решения, откладывающие необратимость (БД на сервис — очень необратимо; границы модулей в монолите — дёшево перерисовать).

Типичные ошибки

Ловушки Saga и распределённые транзакции: микросервисы для 5-инженерной команды (каждый сервис стоит ops + observability; больше дебажите RPC, чем шипите фичи); погоня за паттернами из FAANG-блогов на startup-масштабе (их ограничения не ваши); переписывание "ради clean architecture" без замеренной выгоды (clean ≠ better — только если окупается в изменяемости). Оптимизируйте под следующие 12 месяцев, не под 10x масштаб, которого нет.

Связанные понятия

Полезные ресурсы