АрхитектураРаспределённые системыBackend-разработчик распределённых систем

Может ли сага гарантировать атомарный откат изменений во всех сервисах при сбое одного шага?

Может ли сага гарантировать атомарный откат изменений во всех сервисах при сбое одного шага?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Нет. Сага не обеспечивает атомарный откат: она выполняет последовательность локальных транзакций, а при сбое запускает компенсирующие действия. Поэтому итоговая согласованность достигается постепенно, а промежуточные изменения могут быть видны другим участникам.

Исторический контекст

В распределённой системе отдельные сервисы обычно владеют собственными базами данных. Общая транзакция между ними через двухфазный протокол может удерживать ресурсы, зависеть от координатора и плохо работать при сетевых сбоях или длительных операциях.

Сага появилась как способ разделить длительную бизнес-операцию на локальные транзакции. Вместо общего атомарного отката система определяет действия, компенсирующие уже выполненные шаги.

Постановка проблемы

Например, оформление заказа может включать резервирование товара, списание денег и создание доставки. Если резервирование и списание завершились, а создание доставки не удалось, база одного сервиса не может автоматически откатить изменения в других базах.

Неверно считать компенсацию обычным ROLLBACK. Она сама является отдельной операцией и может завершиться с ошибкой, быть выполнена повторно или увидеть уже изменившееся состояние. Кроме того, некоторые действия необратимы: отправленное письмо нельзя надёжно отменить, а физически отгруженный товар нельзя мгновенно вернуть в исходное состояние.

Подробное решение

Сага состоит из локальных транзакций и компенсирующих операций. Если шаги обозначить как A, B и C, то при ошибке на C система обычно выполняет компенсации для B и A в обратном порядке: не отменяет единую транзакцию, а проводит новые бизнес-операции, возвращающие состояние настолько близко к исходному, насколько это возможно.

Сагой можно управлять через оркестратор, который хранит состояние процесса и явно вызывает шаги, либо через хореографию, где сервисы реагируют на события друг друга. Оркестратор проще контролировать и наблюдать, но он становится важным компонентом процесса. Хореография уменьшает центральную координацию, однако усложняет понимание зависимостей, диагностику и изменение сценария.

Каждый шаг и компенсация должны иметь устойчивый идентификатор и быть идемпотентными: повтор после тайм-аута не должен приводить к повторному списанию или двойному возврату. Для надёжной публикации событий часто применяют паттерн транзакционного исходящего сообщения: факт изменения и сообщение о нём фиксируются в одной локальной транзакции, а отдельный доставщик повторяет отправку.

Система должна хранить состояние саги: выполненные шаги, попытки, ошибки и результат компенсаций. Нужны повторные попытки с ограничением, дедлеттер или ручная обработка, а также понятные состояния вроде ожидает компенсации и требует вмешательства.

Главный компромисс — ослабление изоляции. Другие сервисы могут увидеть промежуточный результат, поэтому бизнес-процесс должен допускать такие состояния или скрывать их через статусы, резервирование и проверки. Сага обеспечивает не атомарность, а согласованность бизнес-процесса в конечном счёте, если компенсации достижимы и корректно спроектированы.

Ситуация из практики

Интернет-магазин сначала резервирует товар, затем списывает оплату и после этого создаёт доставку. При недоступности службы доставки возможны три варианта.

Двухфазная транзакция дала бы более сильную атомарность, но потребовала бы совместимого участия всех хранилищ, удерживала бы ресурсы и была бы чувствительна к отказу координатора. Хореографическая сага уменьшила бы центральную связанность, но сделала бы порядок действий и обработку исключений менее прозрачными. Простое повторение всей операции опасно двойным списанием и повторным резервированием.

Практичным решением стала оркестрируемая сага: оркестратор фиксирует идентификатор заказа и состояние шага, платёжный сервис поддерживает идемпотентное списание и возврат, а сообщения публикуются через транзакционный исходящий журнал. Если доставка не создаётся, оркестратор отменяет оплату и освобождает резерв. Заказы переходят в состояние завершён, отменён или требует ручного вмешательства, поэтому неудачные компенсации не теряются.

Что кандидаты часто упускают

  1. Вопрос: Что произойдёт, если сама компенсирующая операция завершится ошибкой?

Ответ: Сага не должна считаться автоматически отменённой. Компенсацию нужно повторять безопасным способом, используя идемпотентность и устойчивое хранение состояния. После исчерпания автоматических попыток процесс переводят в состояние, требующее ручного вмешательства или специальной процедуры восстановления.

Важно различать временный сбой и постоянную бизнес-ошибку. Сетевой тайм-аут может означать, что операция уже выполнена, поэтому без идемпотентного ключа повтор способен создать новый побочный эффект.

  1. Вопрос: Почему компенсации обычно выполняются в обратном порядке?

Ответ: Поздние шаги часто зависят от результатов ранних. Если сначала отменить резервирование товара, а затем попытаться отменить оплату, между этими действиями можно получить состояние, в котором деньги уже списаны, а товар снова доступен для другой покупки.

Обратный порядок не является универсальной гарантией корректности: конкретный бизнес-процесс может требовать другой последовательности или независимых компенсаций. Его используют как безопасное базовое правило для обращения цепочки зависимостей.

  1. Вопрос: Почему идемпотентность компенсации не делает сагу атомарной?

Ответ: Идемпотентность лишь делает повтор одной операции безопасным с точки зрения её эффекта. Она не объединяет изменения разных сервисов в единую неделимую транзакцию и не предотвращает промежуточное наблюдение состояния.

Например, повторный возврат денег может корректно оставить один итоговый возврат, но между списанием и возвратом пользователь или другой сервис всё равно мог увидеть временно изменённый баланс. Атомарность потребовала бы, чтобы все изменения стали видимыми одновременно или не стали видимыми вовсе.