Настройка dead-letter exchanges и retry queues
Используйте dead-letter exchanges (DLX) для перемещения сообщений из основного пути обработки после событий negative acknowledgement, expiration или переполнения очереди. Сочетайте DLX с retry queues, когда рабочей нагрузке требуется отложить вторую или последующую попытку доставки.
Это руководство разделяет две задачи:
- dead-letter queue (DLQ) для сообщений, которые должны прекратить обычную обработку.
- retry queue для сообщений, которые должны вернуться в рабочую очередь после задержки.
Содержание
Применимые сценарииПроцедура1. Объявите exchanges2. Объявите рабочую очередь и DLQ3. Объявите retry queue4. Реализуйте решение приложения о повторной попытке5. Проверьте топологиюРекомендуемые практикиСвязанная информацияПрименимые сценарии
Используйте этот шаблон, если вам нужно одно или несколько из следующего:
- Помещать навсегда неудачные сообщения в DLQ для анализа.
- Откладывать повторные попытки вместо немедленного повторного помещения сообщения в очередь.
- Держать основную очередь свободной от сообщений, которые repeatedly fail.
Не полагайтесь на бесконечные циклы basic.nack или basic.reject с requeue=true. Они создают тесные циклы повторной доставки и усложняют контроль состояния очереди.
Процедура
В этом примере:
- Producers публикуют рабочие сообщения в
orders.work. - Consumers читают из
orders.q. - Постоянные ошибки отправляются в
orders.dlqчерезorders.dlx. - Временные ошибки повторно публикуются приложением в
orders.retry. orders.retry.30sхранит повторно отправленные сообщения 30 секунд, а затем отправляет их обратно вorders.workчерез dead-lettering.
1. Объявите exchanges
2. Объявите рабочую очередь и DLQ
Рабочая очередь отправляет failed messages в orders.dlx с routing key orders.failed:
Свяжите очереди:
Когда consumer отклоняет сообщение из orders.q с requeue=false, RabbitMQ отправляет сообщение в orders.dlq через dead-lettering.
3. Объявите retry queue
Создайте retry queue, которая задерживает повторную доставку на 30 секунд:
Свяжите retry queue:
4. Реализуйте решение приложения о повторной попытке
Используйте логику приложения, чтобы определить, является ли сбой временным или постоянным:
- Для временных сбоев публикуйте сообщение в
orders.retryс routing keyorders.30s. - Для постоянных сбоев отклоняйте сообщение из
orders.qсrequeue=falseлибо явно публикуйте его в путь DLQ.
Когда consumer повторно публикует сообщение при временном сбое в orders.retry, он должен подтверждать исходную доставку только после успешной публикации retry. В production используйте publisher confirms для пути повторной публикации, чтобы consumer не удалял исходное сообщение до того, как RabbitMQ примет копию для retry.
Если публикация retry завершается сбоем или confirm не получен, не подтверждайте исходную доставку положительно. Повторно поместите сообщение в очередь или повторите попытку в соответствии с вашей политикой обработки ошибок.
Даже при использовании publisher confirms дубликаты по-прежнему возможны во время reconnects или частичных сбоев. Consumers и downstream processors должны оставаться idempotent.
RabbitMQ не предоставляет универсальный встроенный счетчик повторных попыток для classic queues. Если вам нужен максимальный лимит повторных попыток, используйте логику приложения, проверяйте заголовок x-death или при необходимости используйте delivery limits quorum queue.
5. Проверьте топологию
Проверьте exchanges, queues и bindings:
Рекомендуемые практики
- Используйте dedicated DLQ для анализа и повторного воспроизведения.
- Используйте delayed retry queues вместо немедленных циклов повторного помещения в очередь.
- Делайте consumers idempotent, поскольку retries и failovers могут создавать дублирующиеся доставки.
- Определяйте в приложении, когда сообщение должно прекратить повторные попытки.
- Отслеживайте рост DLQ. Растущая DLQ обычно указывает на проблему в коде, схеме или зависимости.