Какие типы гарантии доставки сообщений существуют в брокерах сообщений
Что проверяют
Понимаете ли вы, что гарантия доставки это свойство всей цепочки, от продюсера через брокер к потребителю и его базе, а не галочка в конфиге брокера. Вопрос отсеивает тех, кто верит в exactly-once как в настройку. Уточняющий вопрос стандартный: как сделать обработку идемпотентной.
Как отвечать
- at-most-once: подтверждение до обработки или отправка без подтверждения вовсе. Дубликатов нет, потери возможны. Годится для метрик и телеметрии;
- at-least-once: подтверждение после успешной обработки, при падении сообщение приходит снова. Рабочий режим по умолчанию почти везде;
- exactly-once: в распределённой системе в общем виде недостижимо, это следствие задачи о двух генералах. На практике достигается либо транзакционно внутри одной системы, либо схемой «эффективно один раз», то есть at-least-once плюс идемпотентный потребитель.
Дальше конкретика. В Kafka идемпотентный продюсер (enable.idempotence=true, включён по умолчанию с версии 3.0) убирает дубликаты от повторных попыток внутри партиции; acks=all вместе с min.insync.replicas=2 защищает от потери при смене лидера; транзакции и isolation.level=read_committed дают exactly-once для сценария «прочитал, обработал, записал» внутри самой Kafka, но не покрывают запись во внешнюю базу. RabbitMQ предлагает publisher confirms на стороне отправителя, ручной basic.ack на стороне получателя и quorum-очереди, exactly-once он не обещает. Для связки с базой называйте transactional outbox, дедупликацию по ключу сообщения с ограниченным временем жизни и upsert вместо insert.
Где спотыкаются
Называют exactly-once настройкой брокера и не могут объяснить, что происходит при падении потребителя между записью в базу и подтверждением.
Оставляют автокоммит смещения. Оффсет уезжает вперёд по таймеру, приложение падает в середине пачки, и часть сообщений теряется навсегда.
Забывают про очередь недоставленных сообщений и про порядок. Повторная отправка после ошибки переставляет сообщения в партиции, если не блокировать обработку до успеха.