Подтверждения
Подтверждения (Acknowledgments) в RabbitMQ делятся на два типа: Publisher Confirms (подтверждение от брокера издателю о получении сообщения) и Consumer Acks (подтверждение от потребителя брокеру об успешной обработке). В комбинации с персистентностью и ручным подтверждением (manual ack) они обеспечивают гарантию доставки at-least-once, а для достижения exactly-once требуется добавить идемпотентность на стороне потребителя.
Введение: Расписка в получении
Представьте, что вы отправляете ценную посылку курьерской службой. Вы не просто бросаете её в ящик и надеетесь. Вы передаёте курьеру, он ставит отметку в накладной, вы получаете уведомление, что посылка принята. Когда курьер доставляет посылку адресату, тот расписывается в получении. Вы знаете, что посылка дошла.
В мире сообщений без подтверждений вы никогда не знаете, дошло ли сообщение. Может, оно потерялось в сети. Может, брокер упал. Может, потребитель получил, но упал до обработки.
Подтверждения (Acknowledgments) — это механизм, который даёт гарантии. Producer получает подтверждение от брокера: “Сообщение получено и сохранено”. Consumer отправляет подтверждение брокеру: “Сообщение обработано, можно удалять”.
В RabbitMQ подтверждения — это ключевой механизм обеспечения надёжности. Без них сообщения могут теряться, дублироваться, обрабатываться несколько раз. С ними вы можете строить системы, где потеря данных недопустима.
Для системного аналитика понимание подтверждений позволяет оценить гарантии доставки, которые даёт система, и выбрать правильную стратегию для разных типов сообщений.
Два вида подтверждений
| Вид | Участники | Что подтверждает | Зачем |
|---|---|---|---|
| Publisher Confirms | Producer → Broker | Сообщение получено брокером | Producer знает, что сообщение не потерялось по пути |
| Consumer Acks | Consumer → 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 ack | Consumer сам решает, когда подтвердить | Сообщение может зависнуть (если забыли ack) |
Стратегии подтверждений
Подтверждать после обработки:
Алгоритм:
1. Получить сообщение
2. Обработать
3. Подтвердить
Плюсы: Сообщение не потеряется при падении
Минусы: Если обработка долгая — сообщение долго в unackedПодтверждать до обработки (не рекомендуется):
Алгоритм:
1. Получить сообщение
2. Подтвердить
3. Обработать
Риск: При падении после подтверждения сообщение потеряноПодтверждать пачкой (batch ack):
Алгоритм:
1. Получить 10 сообщений
2. Обработать все
3. Подтвердить все (multiple=true)
Плюсы: Быстрее
Минусы: При ошибке нужно разбираться, какие обработаны, какие нетReject и Nack
| Действие | Команда | Что происходит |
|---|---|---|
| Отклонить с requeue | basic.reject(requeue=true) | Сообщение возвращается в очередь |
| Отклонить без requeue | basic.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: Подтверждение до обработки
Подтвердили, потом обрабатывали. При падении сообщение потеряно.
Решение: Подтверждать после обработки.
Резюме
Два вида подтверждений: publisher confirms (producer → broker) и consumer acks (consumer → broker).
Publisher confirms: producer получает подтверждение, что сообщение доставлено в брокер. Режимы: single, batch, async.
Consumer acks: consumer подтверждает, что сообщение обработано. auto-ack (опасно), manual ack (надёжно).
Без подтверждений: сообщения могут теряться. С подтверждениями — at-least-once.
Для exactly-once нужна идемпотентность на consumer + at-least-once.
Prefetch (QoS) ограничивает количество неподтверждённых сообщений у consumer.
Reject позволяет вернуть сообщение в очередь (requeue=true) или отправить в DLQ (requeue=false).