Перейти к содержимому

Подтверждения

Подтверждения (Acknowledgments) в RabbitMQ делятся на два типа: Publisher Confirms (подтверждение от брокера издателю о получении сообщения) и Consumer Acks (подтверждение от потребителя брокеру об успешной обработке). В комбинации с персистентностью и ручным подтверждением (manual ack) они обеспечивают гарантию доставки at-least-once, а для достижения exactly-once требуется добавить идемпотентность на стороне потребителя.

Введение: Расписка в получении

Представьте, что вы отправляете ценную посылку курьерской службой. Вы не просто бросаете её в ящик и надеетесь. Вы передаёте курьеру, он ставит отметку в накладной, вы получаете уведомление, что посылка принята. Когда курьер доставляет посылку адресату, тот расписывается в получении. Вы знаете, что посылка дошла.

В мире сообщений без подтверждений вы никогда не знаете, дошло ли сообщение. Может, оно потерялось в сети. Может, брокер упал. Может, потребитель получил, но упал до обработки.

Подтверждения (Acknowledgments) — это механизм, который даёт гарантии. Producer получает подтверждение от брокера: “Сообщение получено и сохранено”. Consumer отправляет подтверждение брокеру: “Сообщение обработано, можно удалять”.

В RabbitMQ подтверждения — это ключевой механизм обеспечения надёжности. Без них сообщения могут теряться, дублироваться, обрабатываться несколько раз. С ними вы можете строить системы, где потеря данных недопустима.

Для системного аналитика понимание подтверждений позволяет оценить гарантии доставки, которые даёт система, и выбрать правильную стратегию для разных типов сообщений.

Два вида подтверждений

ВидУчастникиЧто подтверждаетЗачем
Publisher ConfirmsProducer → BrokerСообщение получено брокеромProducer знает, что сообщение не потерялось по пути
Consumer AcksConsumer → BrokerСообщение обработаноBroker знает, что можно удалить сообщение

Publisher Confirms (Подтверждения от издателя)

Что это

Механизм, с помощью которого producer получает подтверждение от брокера, что сообщение получено и (опционально) записано на диск.

Без подтверждений

    sequenceDiagram
    participant P as Producer
    participant B as Broker
    
    P->>B: Отправить сообщение
    Note over P,B: Producer не знает, дошло ли
  

Риски:

РискЧто происходит
Сетевые проблемыСообщение не долетело до брокера
Брокер упалСообщение потеряно
ПерегрузкаСообщение отброшено

С подтверждениями

    sequenceDiagram
    participant P as Producer
    participant B as Broker
    
    P->>B: Отправить сообщение
    B-->>P: ACK (подтверждение)
    Note over P: Producer знает, что сообщение доставлено
  

Режимы publisher confirms

РежимКак работаетГарантияПроизводительность
Обычный (single)Ждём подтверждение после каждого сообщенияВысокаяНизкая
Пакетный (batch)Отправили N сообщений, ждём одно подтверждение на всеВысокаяСредняя
АсинхронныйОтправляем, подтверждения приходят в callbackВысокаяВысокая

Обычный режим (single)

Алгоритм:
  1. Отправить сообщение
  2. Ждать подтверждения
  3. Отправить следующее

Плюсы:
  - Простота
  - Каждое сообщение подтверждено

Минусы:
  - Медленно (задержка на каждое сообщение)

Пакетный режим (batch)

Алгоритм:
  1. Отправить 100 сообщений
  2. Ждать одного подтверждения на все
  3. Если подтверждение пришло — все доставлены
  4. Если нет — повторить всю пачку

Плюсы:
  - Быстрее, чем single

Минусы:
  - При ошибке нужно повторять всю пачку
  - Непонятно, какое сообщение из пачки потерялось

Асинхронный режим

Алгоритм:
  1. Отправить сообщение
  2. Не ждать
  3. При получении подтверждения вызвать callback
  4. При получении nack вызвать другой callback

Плюсы:
  - Максимальная производительность

Минусы:
  - Сложнее реализовать

Подтверждения и персистентность

Тип сообщенияПодтверждениеГарантия
Transient (в памяти)ПришлоСообщение в памяти брокера
Persistent (на диск)ПришлоСообщение на диске

Рекомендация: Для критичных данных используйте persistent + publisher confirms.

Consumer Acks (Подтверждения от потребителя)

Что это

Механизм, с помощью которого consumer подтверждает брокеру, что сообщение обработано. Только после этого брокер удаляет сообщение из очереди.

Без подтверждений (auto-ack)

    sequenceDiagram
    participant B as Broker
    participant C as Consumer
    
    B->>C: Отправить сообщение
    Note over B: Сообщение удалено из очереди
    C->>C: Обработка (может упасть)
    Note over B,C: Если обработка упала — сообщение потеряно
  

С подтверждениями (manual ack)

    sequenceDiagram
    participant B as Broker
    participant C as Consumer
    
    B->>C: Отправить сообщение
    C->>C: Обработка
    C->>B: ACK
    Note over B: Сообщение удалено
  

Что происходит без ACK

Сценарий:
  1. Consumer получил сообщение
  2. Соединение оборвалось (consumer упал)
  3. Сообщение возвращается в очередь
  4. Другой consumer получит его

Режимы подтверждений

РежимПоведениеРиск
auto-ackПодтверждение сразу после полученияПотеря сообщения при падении consumer
manual ackConsumer сам решает, когда подтвердитьСообщение может зависнуть (если забыли ack)

Стратегии подтверждений

Подтверждать после обработки:

Алгоритм:
  1. Получить сообщение
  2. Обработать
  3. Подтвердить

Плюсы: Сообщение не потеряется при падении
Минусы: Если обработка долгая — сообщение долго в unacked

Подтверждать до обработки (не рекомендуется):

Алгоритм:
  1. Получить сообщение
  2. Подтвердить
  3. Обработать

Риск: При падении после подтверждения сообщение потеряно

Подтверждать пачкой (batch ack):

Алгоритм:
  1. Получить 10 сообщений
  2. Обработать все
  3. Подтвердить все (multiple=true)

Плюсы: Быстрее
Минусы: При ошибке нужно разбираться, какие обработаны, какие нет

Reject и Nack

ДействиеКомандаЧто происходит
Отклонить с requeuebasic.reject(requeue=true)Сообщение возвращается в очередь
Отклонить без requeuebasic.reject(requeue=false)Сообщение удаляется или в DLQ
Nack (множественное отклонение)basic.nack(multiple=true)Отклонить пачку сообщений

Когда использовать reject:

requeue=true:
  - Временная ошибка (база данных недоступна)
  - Сообщение можно обработать позже

requeue=false:
  - Сообщение невалидно (нельзя обработать в принципе)
  - Превышено количество попыток

Гарантии доставки и подтверждения

At-most-once (не более одного раза)

Настройка:
  - auto-ack (consumer)
  - Нет publisher confirms (или acks=0)

Риск:
  - Сообщение может потеряться
  - Дубликатов нет

At-least-once (не менее одного раза)

Настройка:
  - manual ack (consumer)
  - publisher confirms

Риск:
  - Сообщение не потеряется
  - Возможны дубликаты (если ack потерялся)

Exactly-once (ровно один раз)

Настройка:
  - manual ack + идемпотентность на consumer
  - publisher confirms

Дубликаты возможны, но обработка должна быть идемпотентной.

Подтверждения и производительность

Влияние publisher confirms

РежимЗадержкаПропускная способность
Без подтвержденийМинимальнаяМаксимальная
Single confirmВысокаяНизкая
Batch confirmСредняяСредняя
Async confirmНизкаяВысокая

Влияние consumer acks

РежимЗадержкаРиск потери
auto-ackМинимальнаяВысокий
manual ack (каждое сообщение)СредняяНизкий
manual ack (batch)НизкаяСредний

Prefetch (QoS)

Ограничение количества неподтверждённых сообщений у consumer.

prefetch_count = 10:
  - Consumer получил 10 сообщений
  - Не подтвердил ни одного
  - Больше не получит, пока не подтвердит

Зачем:
  - Защита от перегрузки consumer
  - Равномерное распределение нагрузки

Подтверждения и Dead Letter Queue

Путь сообщения в DLQ

1. Consumer получил сообщение
2. Ошибка при обработке
3. Consumer отклонил (reject с requeue=false)
4. Сообщение попадает в DLQ

Настройка DLQ для неподтверждённых сообщений

Очередь:
  x-dead-letter-exchange: dlx
  x-dead-letter-routing-key: failed

Политика:
  - Если consumer не подтвердил в течение x-consumer-timeout
  - Сообщение попадает в DLQ

Практические сценарии

Сценарий 1: Критичные данные (платежи)

Producer:
  - publisher confirms (async)
  - persistent messages

Consumer:
  - manual ack
  - ack после записи в БД
  - reject с requeue=false при ошибке (в DLQ)

Сценарий 2: Логи и метрики

Producer:
  - без подтверждений (можно потерять)

Consumer:
  - auto-ack

Сценарий 3: Очередь задач (workers)

Producer:
  - publisher confirms (batch)

Consumer:
  - manual ack
  - ack после выполнения задачи
  - reject с requeue=true при временной ошибке

Мониторинг подтверждений

Метрики

МетрикаЧто показывает
unacknowledged_messagesСообщения, отправленные, но не подтверждённые
delivered_unacknowledgedСообщения, доставленные без ack
publish_confirmКоличество подтверждённых публикаций

Алерты

СитуацияДействие
unacknowledged растётConsumer не успевает или завис
publish confirm долго нетПроблемы с брокером или сетью

Распространённые ошибки

Ошибка 1: auto-ack для критичных данных

Consumer получил, auto-ack отправил, обработка упала — сообщение потеряно.

Решение: manual ack.

Ошибка 2: Забытый ack

Consumer обработал, но забыл подтвердить. Сообщение висит в unacked, очередь растёт.

Решение: Всегда ack в блоке finally.

Ошибка 3: reject без DLQ

Consumer отклонил с requeue=false, сообщение потеряно.

Решение: Настроить DLQ.

Ошибка 4: Слишком большой prefetch

prefetch=1000, consumer не успевает, unacked растёт.

Решение: Установить prefetch в соответствии с мощностью consumer.

Ошибка 5: Подтверждение до обработки

Подтвердили, потом обрабатывали. При падении сообщение потеряно.

Решение: Подтверждать после обработки.

Резюме

  1. Два вида подтверждений: publisher confirms (producer → broker) и consumer acks (consumer → broker).

  2. Publisher confirms: producer получает подтверждение, что сообщение доставлено в брокер. Режимы: single, batch, async.

  3. Consumer acks: consumer подтверждает, что сообщение обработано. auto-ack (опасно), manual ack (надёжно).

  4. Без подтверждений: сообщения могут теряться. С подтверждениями — at-least-once.

  5. Для exactly-once нужна идемпотентность на consumer + at-least-once.

  6. Prefetch (QoS) ограничивает количество неподтверждённых сообщений у consumer.

  7. Reject позволяет вернуть сообщение в очередь (requeue=true) или отправить в DLQ (requeue=false).

Проверка знаний

Вопрос 1 из 4
Зачем в RabbitMQ нужны подтверждения (acks / confirms)?
Что является риском auto-ack?
Что даёт manual ack со стороны consumer?
Зачем publisher confirms нужны отправителю?

Вопросы, где были ошибки