Какие методы микросервисного взаимодействия позволяют нивелировать минусы распределенных транзакций
Что проверяют
Понимаете ли вы, почему в микросервисах уходят от распределённых транзакций (2PC), и чем их заменяют, не теряя данные. Следом почти всегда спрашивают, как гарантировать, что запись в базу и отправка события не разойдутся.
Как отвечать
Сначала коротко про минусы 2PC: координатор становится точкой отказа, ресурсы заблокированы на время голосования, а брокеры вроде Kafka в XA-транзакциях не участвуют. Замена собирается из нескольких приёмов:
- сага: цепочка локальных транзакций, у каждого шага есть компенсирующее действие. В хореографии сервисы реагируют на события друг друга, в оркестрации процесс явно ведёт один сервис. Для оркестрации в Node.js берут Temporal с TypeScript SDK или свою машину состояний в базе;
- transactional outbox: событие пишется в таблицу
outboxв той же транзакции, что и бизнес-данные, а отдельный релей или CDC через Debezium публикует его в Kafka или RabbitMQ. Проблема двойной записи исчезает; - идемпотентные потребители: доставка почти всегда at-least-once, поэтому обработчик хранит идентификаторы обработанных сообщений (inbox), и повтор не создаёт второй платёж;
- идемпотентные API: заголовок
Idempotency-Keyна синхронных вызовах, чтобы ретрай клиента был безопасен; - статусы вместо блокировок: заказ живёт в состоянии
PENDING, пока сага не завершилась, и другие процессы не принимают решений по промежуточным данным.
Скажите прямо, что цена всего этого eventual consistency: какое-то время данные в сервисах расходятся, и продукт должен это выдерживать.
Где спотыкаются
Называют CQRS и event sourcing способом решить распределённые транзакции. Это модели хранения и чтения, согласованность между сервисами сами по себе они не дают.
В обработчике сначала выполняют коммит в базу, а потом await producer.send(). Процесс падает между этими строками, и событие теряется навсегда, ровно этот случай закрывает outbox.
Проектируют компенсацию как откат. Отправленное письмо или списанные деньги не отменить, компенсация это новое действие: возврат, отмена брони, уведомление. Её тоже нужно делать идемпотентной, потому что она может прийти дважды.