Какие типы гарантии доставки сообщений существуют в брокерах сообщений
Что проверяют
Знаете ли вы, что гарантия доставки задаётся не галочкой в брокере, а тем, когда продюсер считает сообщение отправленным и когда консьюмер подтверждает обработку. Следом почти наверняка спросят: «как у вас обрабатывались дубли?».
Как отвечать
Назовите три уровня и сразу механизм, который к ним приводит:
- at most once: сообщение может потеряться, но не повторится. Консьюмер подтверждает получение до обработки: в Kafka коммитит offset заранее, в Celery так ведёт себя задача по умолчанию. Годится для метрик и логов;
- at least once: не теряется, но может прийти повторно. Подтверждение после успешной обработки: ручной
ackв RabbitMQ (auto_ack=Falseвpika), коммит offset после обработки в Kafka,acks_late=Trueв Celery. Самый частый рабочий режим; - exactly once: в чистом виде есть только внутри Kafka. Идемпотентный продюсер (
enable.idempotence, включён по умолчанию с Kafka 3.0) убирает дубли при повторной отправке, транзакции иisolation.level=read_committedдают атомарную цепочку «прочитал, обработал, записал в Kafka». Как только эффект уходит наружу, в базу или платёжный API, гарантия заканчивается.
Главная мысль ответа: на практике делают at least once плюс идемпотентный обработчик. У сообщения есть уникальный ключ, обработчик пишет его в таблицу с уникальным индексом в той же транзакции, что и результат, и повтор просто пропускается. Со стороны отправки дополняют паттерном outbox: событие пишется в базу вместе с бизнес-данными, а отдельный процесс публикует его в брокер.
Для надёжности самого брокера упомяните acks=all у продюсера Kafka, а в RabbitMQ publisher confirms, durable-очереди и persistent-сообщения.
Где спотыкаются
Говорят «у нас exactly once, потому что Kafka». Внешняя база в транзакцию Kafka не входит, и без идемпотентного обработчика дубли всё равно будут.
Приводят платежи как пример, где дубли приемлемы. Там как раз двойное списание хуже всего, поэтому нужен ключ идемпотентности.
Включают acks_late=True в Celery и не делают задачи идемпотентными. Если воркер упадёт посреди задачи, она выполнится ещё раз и, например, отправит письмо повторно.