Как обеспечить атомарность бизнес-логики в микросервисной архитектуре при взаимодействии через REST API без поддержки транзакций?
Что проверяют
Понимаете ли вы, что без распределённой транзакции атомарность заменяется согласованностью в конечном счёте, и знаете ли механизмы, которые её обеспечивают. Следом спрашивают: сервис ответил таймаутом, списание прошло или нет.
Как отвечать
Честно скажите: атомарности в смысле ACID через несколько сервисов по REST не будет. 2PC и XA поверх HTTP не работают и держат блокировки, поэтому задачу решают набором приёмов:
- Saga: цепочка локальных транзакций, у каждого шага есть компенсация. Оркестрацию (координатор хранит состояние и решает, что дальше) проще отлаживать, хореография на событиях меньше связывает сервисы. В Java для оркестрации берут Temporal, Camunda или пишут свой координатор с состоянием в базе;
- идемпотентность: клиент шлёт ключ в заголовке
Idempotency-Key, сервер хранит его под уникальным ограничением и на повтор отдаёт сохранённый результат. Без этого любой ретрай опасен; - transactional outbox: бизнес-данные и событие пишутся в таблицу
outboxодной локальной транзакцией, отдельный процесс или Debezium доставляет событие в брокер. Так исчезает двойная запись «в базу и в Kafka»; - резервирование (TCC): сначала резерв (деньги захолдированы, товар отложен), потом подтверждение или отмена. Промежуточное состояние видно всем как
PENDING; - ретраи с бэкоффом: через Resilience4j и только для идемпотентных вызовов;
- сверка: фоновая джоба находит зависшие саги и доводит их до конца.
Отдельно проговорите таймаут: это неизвестный исход, а не ошибка. Правильная реакция: повторить с тем же ключом или запросить статус, а не запускать компенсацию вслепую.
Где спотыкаются
Надеются на @Transactional. Он покрывает только локальную базу: HTTP-вызов внутри него не откатится, а соединение с базой висит всё время ожидания ответа.
Пишут компенсацию, которая сама может упасть и не идемпотентна. Её тоже нужно ретраить и логировать.
Называют Event Sourcing способом получить атомарность. Это модель хранения состояния, согласованность между сервисами она сама по себе не даёт.