Как обеспечиваются гарантии доставки при использовании хореографии и оркестрации в микросервисах
Что проверяют
Понимаете ли вы, что гарантию доставки даёт не выбор между хореографией и оркестрацией, а механизмы под ними: брокер, outbox и идемпотентные обработчики. Следом спрашивают, что будет, если сервис записал данные в базу и упал до публикации события.
Как отвечать
Начните с уровней гарантий. «Не больше одного раза» теряет сообщения, «хотя бы один раз» даёт дубли, а «ровно один раз» на практике собирают из «хотя бы одного раза» и идемпотентной обработки. Общие для обоих стилей механизмы:
- transactional outbox: событие пишется в таблицу outbox в той же транзакции, что и бизнес-данные, а отдельный процесс доставляет его в брокер. Так исчезает проблема двойной записи. В .NET готовые реализации есть в MassTransit, NServiceBus и CAP;
- inbox и идемпотентность: получатель запоминает
MessageIdобработанных сообщений или делает операцию идемпотентной по природе (upsert, проверка статуса); - подтверждения брокера: в RabbitMQ durable-очереди, persistent-сообщения, publisher confirms и ручной
ackпосле обработки; в Kafkaacks=all, идемпотентный продюсер и коммит смещения только после обработки; - повторы и DLQ: повтор с экспоненциальной задержкой, после лимита сообщение уходит в очередь ошибок, а не теряется.
Разница между стилями в том, где живёт состояние процесса. В оркестрации его хранит оркестратор: сага MassTransit с персистентным хранилищем, Temporal или Durable Functions. Он видит, какой шаг не подтвердился, повторяет его и запускает компенсации. В хореографии целиком состояния нет ни у кого, поэтому нужны сквозной correlation id, таймауты на ожидание ответного события и компенсирующие события у каждого участника.
Где спотыкаются
Говорят, что Kafka или RabbitMQ сами «гарантируют доставку». Брокер отвечает за сохранность принятого сообщения, но не за то, что вы его отправили после коммита в базу.
Обещают exactly-once без оговорок. Повтор после таймаута неизбежен, и без идемпотентного обработчика клиент получит два списания.
Считают сагу распределённой транзакцией. Изоляции у неё нет: промежуточные состояния видны другим, а откат делается компенсацией, которая сама может упасть и тоже требует повторов.