Продюсер RabbitMQ публикует в exchange, а не в очередь напрямую. Binding решает, в какие очереди попадёт сообщение. После ack сообщение исчезает. Prefetch ограничивает, сколько неакнутых сообщений держать на консьюмере.
RabbitMQ rabbitmq собеседование
RabbitMQ — очередь задач, не лог. Продюсер пишет в exchange, а не в очередь напрямую. Exchange сам по себе сообщения не хранит: смотрит тип и binding, кладёт копии в очереди.
Очередь — буфер потребителей. Несколько консьюмеров на одну очередь — competing consumers: брокер раздаёт сообщения. Строгий глобальный порядок между ними не обещан.
После ack сообщение пропадает. Завтра переиграть вчерашний день из той же очереди нельзя. Replay вы строите сами: архив, отдельный лог, повторная публикация из БД.
Пример. Воркер взял задачу «сжать картинку», сделал работу, отправил ack. Сообщения в очереди больше нет. В Kafka после чтения запись в логе осталась бы, пока жив retention.
Типы exchange
- direct — routing key точно совпадает с binding key. Точечная маршрутизация.
- topic — шаблоны вроде
order.*иorder.#. Удобно резать поток по домену. - fanout — копия во все связанные очереди, ключ игнорируется.
- headers — маршрутизация по заголовкам, на практике реже.
Несколько очередей с одним binding получают копии. Это fan-out: каждая очередь — свой буфер и свои консьюмеры. Несколько консьюмеров на одну очередь делят сообщения, а не копируют их. Эти две схемы путают часто.
Пример. Exchange orders типа topic. Ключ order.created попадает в очередь биллинга. Ключ order.shipped — в очередь доставки. Fanout на тот же поток положил бы копию в обе очереди независимо от ключа.
Ack, nack и prefetch
Autoack — брокер считает сообщение доставленным в момент выдачи. Крэш воркера после выдачи и до работы — потеря. Это at-most-once.
Ручной ack после успешной работы — at-least-once. Крэш до ack вернёт сообщение тому же или другому консьюмеру. Дубль возможен. Nack/reject с requeue крутит сообщение снова. Без requeue его можно отправить в DLX — dead letter exchange.
Prefetch (QoS) — сколько неакнутых сообщений брокер может держать на одном канале. Prefetch=1 честнее распределяет работу и снижает throughput. Слишком большой prefetch отдаёт пачку одному толстому воркеру: он забивает память, остальные голодают, при падении пачка вернётся. Prefetch — не размер очереди, а inflight на потребителе.
ch.ExchangeDeclare("orders", "topic", durable, false, false, false, nil)
ch.QueueDeclare("orders.billing", durable, false, false, false, nil)
ch.QueueBind("orders.billing", "orders", "order.created", false, nil)
ch.Qos(20, 0, false) // prefetch: не больше 20 неакнутых
// после работы:
// d.Ack(false) — успех, сообщение уходит
// d.Nack(false, false) — без requeue, дальше DLX если настроен
Topic exchange кладёт order.created в очередь биллинга. QoS ограничивает inflight. После работы — Ack или Nack в DLX.
Publisher confirms — отдельный слой. «Отправил в сеть» не значит «брокер принял на диск». Без confirms и без durable очереди рестарт брокера теряет то, что вы считали опубликованным. Durable очередь плюс persistent message плюс confirm — минимальный разговор про надёжность продюсера.
Типичная ошибка
Недолговечная очередь и рестарт брокера «не должно влиять». Считать ручной ack exactly-once в БД: это at-least-once, без идемпотентного consumer оплата удвоится. В отличие от Kafka, ack’нутое из той же очереди назад не прокрутишь.
На собеседовании
Картинка: producer → exchange → binding → queue → consumer. Prefetch — inflight, не размер очереди. Ack после работы — at-least-once. После ack replay нет.