Какие гарантии доставки сообщений бывают в очередях сообщений?
javaархитектурагарантии доставкиочереди сообщенийпроектирование
Что проверяют
Понимаете ли вы, что гарантия доставки складывается из поведения продюсера, брокера и консьюмера, и что «ровно один раз» почти всегда достигается идемпотентной обработкой, а не магией брокера. Следом спрашивают, как добиться такого эффекта в вашем сервисе на Kafka или RabbitMQ.
Как отвечать
Гарантий три:
- at-most-once, не более одного раза: сообщение может потеряться, но не повторится. Так выходит, если подтверждение уходит до обработки: смещение в Kafka закоммичено или в RabbitMQ включён auto-ack, а потом консьюмер упал;
- at-least-once, хотя бы один раз: подтверждение идёт после обработки, поэтому при сбое сообщение придёт снова. Потерь нет, дубли возможны. Это рабочий режим для большинства систем;
- exactly-once, ровно один раз: эффект обработки наступает один раз, даже если доставок было несколько.
Как это устроено на практике:
- Kafka, продюсер:
acks=allиenable.idempotence=true, оба по умолчанию начиная с Kafka 3.0. Брокер отбрасывает дубли от ретраев продюсера; - Kafka, транзакции:
transactional.idу продюсера иisolation.level=read_committedу консьюмера дают exactly-once в цепочке «прочитал из Kafka, записал в Kafka». На запись во внешнюю базу или вызов API это не распространяется; - RabbitMQ: durable-очереди, persistent-сообщения, publisher confirms при отправке и ручной ack после обработки;
- идемпотентный консьюмер: таблица обработанных идентификаторов с уникальным ключом или upsert по бизнес-ключу в той же транзакции, что и сама обработка;
- transactional outbox: событие пишется в таблицу вместе с бизнес-данными, а отдельный процесс, например Debezium, публикует его в брокер. Так исчезает ситуация «в базу записали, в брокер не отправили».
Где спотыкаются
Говорят, что Kafka даёт exactly-once «из коробки», и не упоминают, что это верно только внутри самой Kafka.
Выбирают at-least-once и не делают обработку идемпотентной: повторная доставка списывает деньги дважды.
Путают гарантии доставки с порядком. Порядок в Kafka сохраняется только внутри партиции, а ретраи и параллельная обработка легко его ломают.