Сегодня разберём один практический кейс. Тема старая, но до сих пор вызывающая недопонимание: почему basic.publish в RabbitMQ по умолчанию не гарантирует доставку сообщения, и как правильно работать с подтверждениями.
🔸 Почему basic.publish не надёжен из коробки
Метод
basic.publish в AMQP 0-9-1 не имеет возвратной части. То есть он работает в режиме fire-and-forget — семантика at most once.RabbitMQ базируется именно на AMQP 0-9-1 (AMQP 1.0 добавлен с версии 4.0, но это в основном надстройки, а не новое поведение).
📌 В отличие от других методов AMQP, у
basic.publish нет пары some-method-ok.Это значит, что отправитель не знает, дошло ли сообщение до брокера.
И да — в 99.999% случаев всё будет хорошо. Но если вам нужна гарантированная доставка, на одном только basic.publish далеко не уедешь.
🔸 Зачем так сделано
AMQP создавали в JPMorgan — под задачи финансового сектора. Там есть сценарии, где огромные потоки данных (например, котировки с частотой 10k+ событий/сек) допускают потерю части сообщений. Для таких задач fire-and-forget — нормальное поведение.
Для строгой гарантированной доставки в спецификации AMQP предусмотрены транзакции.
В AMQP 2.2.3 прямо сказано:
«Success is silent, and failure is noisy. When applications need explicit tracking of success and failure, they should use transactions.»
Но:
🟢 транзакции в RabbitMQ замедляют publish до 250 раз (по данным официальной документации),
🟢 в RabbitMQ транзакции — лишь «простая форма батчинга», без ACID,
🟢 под каждый publish транзакцию заводить бессмысленно.
Итог: транзакции — рудимент, использовать их в RMQ почти никогда не стоит.
🔸 Как это исправили в RabbitMQ
Команда RabbitMQ расширила протокол AMQP и добавила механизм Publisher Confirms — подтверждения на уровне basic.publish.
Это не часть стандарта AMQP, а собственное расширение RabbitMQ.
Но именно оно стало де-факто стандартом для гарантированной доставки сообщений.
🔸 Как работает Publisher Confirms
Канал переводится в режим подтверждений методом:
$channel->confirm_select();После этого RabbitMQ:
считает каждое опубликованное сообщение,
отправляет
ack или nack после обработки,гарантирует, что отправитель узнает результат.
Главное — вызывать:
$channel->wait_for_pending_acks();Он блокирует выполнение, пока брокер не даст ответы по всем сообщениям.
🔗 Хабр
Библиотека пхпшника