Схема по материалу: Как я проверяю риск потери сообщений RabbitMQ: publisher confirms, acknowledgements и dead-lettering
Схема основана на материале «Как я проверяю риск потери сообщений RabbitMQ: publisher confirms, acknowledgements и dead-lettering» и его сигналах. Цепочка наблюдения разделяет принятие публикации брокером, маршрутизацию, выдачу consumer, подтверждение обработки и итог приложения.

Сначала я раскладываю доказательство по границам

В проектах IT Fresh я не называю доставкой один успешный ответ брокера. Я — Семёнов Евгений Сергеевич, технический директор IT Fresh, и в инженерной работе начинаю с карты ответственности: издатель сформировал сообщение, RabbitMQ принял публикацию, exchange нашёл маршрут, очередь сохранила запись, consumer получил delivery, приложение завершило нужную операцию и только затем подтвердило её. На каждой границе нужен свой наблюдаемый факт с общим correlation ID или message ID. Publisher confirm сообщает о взаимодействии издателя с брокером и принятии сообщения соответствующими очередями, но ничего не доказывает о consumer. Consumer acknowledgement, наоборот, относится к участку от RabbitMQ до обработчика и не знает, как издатель сформировал публикацию. Прикладная отметка результата нужна отдельно. Поэтому даже durable queue, persistent message и полученный confirm не означают сквозной бизнес-результат. Они уменьшают конкретные риски хранения, но не заменяют маршрутизацию, обработку и фиксацию результата. Для каждого перехода я заранее записываю владельца факта и источник времени: иначе журналы разных компонентов создают ложный порядок. Если идентификатор не проходит через всю цепь, прямо отмечаю участок как недоказанный, а не восстанавливаю его по близким временным меткам. Так я получаю не обещание без потерь, а проверяемую цепочку свидетельств и явно видимые пробелы.

Publisher confirms и возврат немаршрутизируемой публикации

На стороне издателя я проверяю, включён ли confirm mode, как приложение сопоставляет последовательность публикаций с basic.ack и basic.nack, хранит ли незавершённые подтверждения при разрыве канала и как обрабатывает неопределённый исход. Confirm может быть групповым и асинхронным, поэтому порядок и поле multiple учитываются в клиентской логике, а отсутствие ответа не превращается автоматически в безопасный повтор. Отдельно проверяю публикацию с флагом mandatory. Немаршрутизируемое сообщение тоже может получить publisher confirm: если mandatory не задан, один basic.ack легко принять за успешное попадание в очередь. При mandatory приложение обязано отдельно наблюдать basic.return и связывать возврат с исходным идентификатором; для немаршрутизируемой публикации basic.return доставляется перед положительным publisher basic.ack, когда такой ack применим. Ещё я отделяю отрицательный confirm от возврата: basic.nack означает, что брокер не смог принять ответственность, тогда как basic.return говорит об отсутствии маршрута. Для неопределённого исхода приложение сохраняет состояние попытки, чтобы решение о повторе принималось осознанно и не теряло связь с первым идентификатором. Для Zabbix я беру агрегированные показатели confirm, nack, return, тайм-аутов и ошибок канала из разрешённой телеметрии приложения. Я не придумываю item keys и единый порог: допустимая задержка зависит от клиентской библиотеки, типа очереди и характера потока. Доказательством служит согласованность событий, а не одно зелёное значение.

Граница consumer acknowledgement проходит после обработки

У consumer я сначала устанавливаю фактический режим подписки. При automatic acknowledgement RabbitMQ считает delivery успешной сразу после отправки в сокет; сбой процесса до завершения работы уже не покрывается ручным подтверждением. При manual acknowledgement приложение решает, когда послать basic.ack. В нашей практике безопасная точка находится после той операции, которую команда действительно считает завершением обработки, а не сразу после десериализации или входа в функцию. basic.nack и basic.reject я разбираю вместе с флагом requeue: при false сообщение попадёт в DLX, если тот настроен, иначе будет отброшено; при true возможно повторное получение. Незакрытая delivery при потере канала или соединения также возвращается в очередь в ручном режиме. Поэтому redelivery является ожидаемой частью модели отказов, а consumer должен быть идемпотентным относительно выбранного идентификатора. Отдельно сверяю, что delivery tag подтверждается на том же канале, где был получен: ошибка области канала закрывает его и способна породить повтор. Пакетный acknowledgement с multiple требует особенно ясной границы, поскольку подтверждает сразу несколько незавершённых delivery. Телеметрия должна различать первое получение, повтор, успешную фиксацию, отказ и отправленный ack. Сам факт acknowledgement означает заявление consumer брокеру, но не позволяет извне проверить корректность бизнес-логики без прикладного свидетельства.

Повторы я считаю штатным риском, а не редкой аномалией

Повторная доставка появляется не только из-за явного requeue. Соединение может закрыться после завершения операции, но до получения broker подтверждения, и тогда сообщение придёт снова. Издатель тоже может повторить публикацию после неопределённого исхода confirm. Поэтому я ищу две независимые защиты: корреляцию попыток и идемпотентность обработчика. В телеметрии полезны message ID или correlation ID, признак redelivered, номер попытки на стороне приложения, итог обработки и причина отказа; содержимое сообщения для этого не требуется. Я проверяю, что повтор с тем же идентификатором не создаёт второй необратимый эффект, а наблюдение отличает безопасный повтор от нового сообщения. Реестр обработанных идентификаторов должен подчиняться жизненному циклу приложения: слишком раннее забывание возвращает риск дубля, а безграничное хранение создаёт другую эксплуатационную проблему. Эти границы задаёт владелец данных, мониторинг лишь показывает нарушение принятого правила. Бесконечный requeue опасен: несколько consumers способны быстро гонять delivery по кругу, расходуя CPU и сеть. Однако универсальное число допустимых повторов я не назначаю. Граница выбирается владельцем приложения вместе с правилами dead-lettering. В рабочей среде мы только читаем факты и сопоставляем идентификаторы. Специально отправлять production nack или reject, обрывать соединения, убивать consumers либо узлы запрещено.

DLX проверяю как маршрут отказа, а не как страховочную надпись

Dead-letter exchange начинает работать при определённых условиях: отрицательное подтверждение с requeue false, истечение срока сообщения, превышение лимита длины очереди, а для quorum queue также превышение лимита доставок. Само имя DLX в аргументах ещё не доказывает сохранение: exchange может отсутствовать во время dead-lettering, у исходной очереди могут не быть нужных прав, а у DLX — подходящей привязки к целевой очереди. В результате сообщение способно не попасть туда, где его ожидают. Я read-only сверяю существование exchange, применённую policy, routing key и bindings, не читая payload. Проверяю также, какая именно policy реально совпала с очередью и не перекрыл ли её более приоритетный набор правил. Отсутствие целевой очереди или binding фиксирую как разрыв маршрута, а не как пустой нормальный результат. Для управляемой конфигурации предпочитаю policy: её можно менять без переобъявления очереди. Жёсткие x-arguments требуют изменения приложения и переобъявления, а заданные аргументы имеют приоритет над policy, что важно видеть при расследовании расхождений. Я не предлагаю команды изменения рабочей policy или топологии. Удалять либо менять live DLX, bindings, TTL и лимиты ради проверки запрещено. Счётчики dead-letter событий и состояние целевой очереди помогают локализовать участок, но итог подтверждается корреляцией с прикладными событиями.

Собираю минимум read-only фактов

Для брокера мы используем одобренный Management HTTP API или штатную интеграцию мониторинга по HTTPS. Учётная запись получает только monitoring-доступ и видимость согласованных vhost; права configure, write, read сообщений и административные действия ей не нужны. Секрет хранится в защищённом макросе, TLS-проверка имени и цепочки не отключается. Я собираю метаданные exchanges, queues, policies и bindings, доступные агрегаты publish, return, deliver, redeliver, ack и dead-letter, статус ответа и свежесть данных. Поля предварительно сверяю с фактическим выпуском и разрешённым API. Из приложения поступают обезличенные события с correlation ID или message ID, фазой обработки и кодом исхода; payload, заголовки авторизации и персональные данные в Zabbix не передаются. Доступ к этим идентификаторам тоже ограничивается ответственными ролями, а срок их хранения согласуется с назначением разбора. Ошибку разбора JSON, отказ авторизации и отсутствие новых прикладных событий я вывожу отдельно, чтобы дефект сбора не выглядел как отсутствие потерь. Глубина очереди, messages ready, unacknowledged и consumers остаются диагностическим контекстом, но не доказательством доставки. Интервал и условия событий выбираю по профилю конкретного потока, не объявляя универсальные пороги. Если API или телеметрия перестали обновляться, мониторинг показывает потерю наблюдаемости, а не подставляет последнее значение как текущую истину.

Контролируемая проверка живёт только вне production

Активную проверку я разрешаю только в изолированном непроизводственном vhost с отдельными exchange, очередями, DLX, учётными данными и уникальными correlation ID. До начала фиксируем ожидаемые переходы: routable-публикация получает confirm, для обязательной немаршрутизируемой публикации basic.return наблюдается отдельно и доставляется перед положительным publisher basic.ack, когда такой ack применим, manual ack отправляется после тестовой фиксации, reject с requeue false уходит по заранее созданной DLX-привязке, а безопасный повтор распознаётся как уже обработанный. После каждого шага сверяем журнал приложения и read-only метаданные брокера по идентификатору, не переносим содержимое сообщения. До запуска дополнительно подтверждаем отдельные адреса подключения и права тестовых учётных записей, а издатель ограничиваем известным тестовым exchange. Завершение фиксируем по всем ожидаемым событиям, затем прекращаем тестовый поток и убеждаемся, что незавершённых попыток не осталось. Тестовые сущности не разделяют bindings, policy или consumers с рабочим контуром. В production запрещены purge и delete, намеренные nack или reject, удаление или изменение действующих DLX, TTL и лимитов, остановка consumers, убийство процессов и узлов. Даже вне production проверка прекращается, если видим неожиданную связь с рабочей топологией. Полученный результат подтверждает только выбранные переходы и настройки тестового vhost; он не становится обещанием поведения любого приложения при любом отказе.

Дежурный читает цепочку и сохраняет безопасную границу

При инциденте дежурный сначала проверяет свежесть broker facts и прикладной телеметрии, затем по correlation ID находит публикацию, basic.return при наличии mandatory, confirm или неопределённый исход. После этого он read-only сверяет exchange, маршрут, очередь, policy и bindings, далее ищет delivery, redelivery, результат обработчика и acknowledgement. Если DLX ожидался, проверяет условие dead-lettering, существование exchange и привязки. Очередные счётчики и consumers помогают понять фон, но не закрывают пробел в цепочке. Без согласованного владельцем изменения нельзя повторно публиковать сообщение, подтверждать delivery вручную, менять policy, topology, TTL или лимиты. Откат наших настроек мониторинга ограничен возвратом прежних URL, защищённых макросов, preprocessing, dependent items и условий событий из сохранённой конфигурации; затем проверяется новый свежий read-only ответ. Если менялось тестовое приложение, возвращаем его конфигурацию и удостоверяемся, что тестовые идентификаторы не попали в рабочий поток. Для разбора вашей цепочки доставки и безопасной настройки наблюдаемости свяжитесь с IT Fresh. Сайт: https://itfresh.ru/ ; канал руководителя: https://t.me/ITfresh_Boss ; телефон: tel:+79037296241.

Сигналы, которые сопоставляю

  • Доля и задержка publisher confirms, basic.nack, тайм-ауты ожидания подтверждений и разрывы канала в телеметрии издателя.
  • События basic.return для mandatory-публикаций и связь exchange, routing key, correlation ID или message ID без чтения содержимого сообщения.
  • Режим consumer acknowledgement, basic.ack после завершения нужной обработки, basic.nack или basic.reject, requeue, redelivery и ошибки обработчика.
  • Наличие DLX, применённой policy, привязок целевой dead-letter очереди и признаков dead-lettering по разрешённым данным брокера.
  • Сквозная корреляция публикации, confirm, доставки, результата обработчика и повторов; счётчики очереди и consumers используются только как диагностический контекст.

Отвергнутые альтернативы

  • Принять publisher confirm за подтверждение работы consumerConfirm относится к участку от издателя до RabbitMQ и не знает о consumer; для результата обработки нужны отдельный acknowledgement и прикладное событие с тем же идентификатором.
  • Считать durable queue и persistent message достаточной сквозной защитойЭти свойства вместе с confirms укрепляют сохранность на стороне брокера, но не доказывают маршрутизацию, корректную обработку и фиксацию результата приложением.
  • Проверять доставку по глубине очереди и числу consumersНулевая глубина возможна при отсутствии публикаций или после потери маршрута, а подключённый consumer может не завершать работу; это фон для разбора, а не доказательство доставки.
  • Получать рабочие сообщения через API для сверки содержимогоЧтение payload нарушает границу конфиденциальности и способно повлиять на доставку; достаточно метаданных, агрегатов и прикладной корреляции.
  • Вызвать ошибку непосредственно в рабочем vhostNack, reject, удаление привязки или остановка consumer на рабочем потоке создают реальный риск повторов и потери; активная проверка допустима только в изолированном непроизводственном vhost.

Конфигурация и сбор

Выделенная monitoring-учётная запись RabbitMQ видит только согласованные vhost и read-only метаданные через одобренный HTTPS API; без configure/write/read payload. Секрет доступен ограниченной роли Zabbix и хранится в защищённом макросе.

  • Проверить свежесть и статус разрешённого API-ответа, не принимать кэшированное значение за текущий факт.
  • Собрать метаданные exchanges, queues, policies и bindings, а также доступные агрегаты подтверждений, возвратов, повторных доставок и dead-lettering.
  • Получить из телеметрии издателя и consumer только correlation ID или message ID, фазу, исход и время без payload и секретов.
  • Связать publish, basic.return, confirm, delivery, redelivery, результат обработки, acknowledgement и DLX по одному идентификатору.

Контролируемая проверка и свидетельство

Только в изолированном непроизводственном vhost с отдельной топологией и уникальными correlation ID проверяются routable confirm, mandatory/basic.return, manual ack после тестовой фиксации, безопасный redelivery и DLX. Запрещены purge/delete, production nack/reject, изменение live DLX, bindings, TTL или лимитов, а также остановка consumers и узлов.

Фрагмент рабочего регламента

  • Проверить свежесть Management HTTP API и прикладной телеметрии, ошибки TLS и авторизации; не трактовать старые данные как текущие.
  • По correlation ID или message ID сопоставить publish, mandatory/basic.return, confirm или неопределённый исход без чтения payload.
  • Read-only сверить exchange, routing key, queue, применённую policy, hardcoded x-arguments и bindings; не менять topology.
  • Сопоставить delivery, redelivery, результат обработчика, basic.ack/basic.nack/basic.reject и requeue; проверить ожидаемый DLX-маршрут.
  • Использовать глубину очереди и consumers только как контекст; эскалировать владельцу приложения любой разрыв цепочки.

Откат

Вернуть только сохранённые настройки наблюдения: URL, защищённые макросы, preprocessing, dependent items и условия событий, затем получить свежий read-only ответ и проверить поступление прикладных идентификаторов. Рабочие queue policies, topology, сообщения, consumers и узлы не изменяются. Конфигурация изолированного тестового приложения возвращается отдельно после подтверждения отсутствия связи с production.

Ограничения вывода

Наблюдение показывает подтверждения протокола, конфигурацию маршрута и прикладные отметки, но не даёт абсолютной гарантии отсутствия потерь или правильности бизнес-результата. Publisher confirm не подтверждает consumer processing; acknowledgement остаётся заявлением приложения. Недоступная телеметрия, неверная корреляция и поведение внешних зависимостей оставляют пробелы. Универсальных порогов и вымышленных Zabbix item keys нет.

Источники

  1. RabbitMQ documentation: Consumer Acknowledgements and Publisher Confirms
  2. RabbitMQ documentation: Reliability Guide
  3. RabbitMQ documentation: Dead Letter Exchanges
  4. RabbitMQ documentation: Monitoring
  5. Zabbix documentation: HTTP agent