Backend / Message queues / RabbitMQ / 01_what_is_rabbitmq.md

What is RabbitMQ

Updated 5 interview angles 4 min read source
On this page7
  1. The routing model
  2. Minimal Python example (pika)
  3. Delivery guarantees
  4. What it’s good for
  5. RabbitMQ vs Kafka
  6. Common pitfalls
  7. Interview angle

What is RabbitMQ

A message broker — middleware that lets services communicate by passing messages instead of calling each other directly. RabbitMQ implements AMQP 0-9-1: producers publish to exchanges, which route messages into queues, from which consumers receive them. It’s the classic choice for task queues and request-style routing where you need flexible delivery, not a replayable log.

For routing depth see RabbitMQ Exchanges, Queues, DLX, and Quorum Queues; for interview Q&A see RabbitMQ — Common Interview Questions and Answers.

The routing model

The thing that distinguishes RabbitMQ: producers never publish to a queue directly. They publish to an exchange, and bindings decide which queues receive the message.

text
Producer ──► Exchange ──(binding by routing key)──► Queue ──► Consumer

                  ├──► Queue B ──► Consumer 2
                  └──► Queue C ──► Consumer 3
Concept Role
Producer publishes a message (body + routing key)
Exchange receives messages, routes them to queues by rules
Binding a rule linking an exchange to a queue (often with a routing-key pattern)
Queue buffers messages until a consumer acks them
Consumer receives and acknowledges messages

Exchange types

Type Routing
direct exact routing-key match
topic wildcard match (order.*.created) — the workhorse
fanout broadcast to every bound queue (ignores routing key)
headers match on message headers instead of routing key

Minimal Python example (pika)

python
import pika

conn = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
ch = conn.channel()
# survives broker restart
ch.queue_declare(queue="tasks", durable=True)

# Producer
ch.basic_publish(
    exchange="",                                       # default direct exchange
    routing_key="tasks",                               # → queue named "tasks"
    body="do work",
    # persistent message
    properties=pika.BasicProperties(delivery_mode=2),
)

# Consumer
def handle(ch, method, props, body):
    process(body)
    # ack AFTER success
    ch.basic_ack(delivery_tag=method.delivery_tag)

# fair dispatch, one at a time
ch.basic_qos(prefetch_count=1)
ch.basic_consume(queue="tasks", on_message_callback=handle)
ch.start_consuming()

Delivery guarantees

RabbitMQ is at-least-once when you use manual acks. The consumer acks only after successfully processing; if it crashes first, the unacked message is requeued and redelivered. That means duplicates happen — consumers must be idempotent.

Durability needs three things together, or you still lose messages:

  1. Durable queue (durable=True) — queue survives restart.
  2. Persistent messages (delivery_mode=2) — message written to disk.
  3. Manual ack — broker keeps the message until the consumer confirms.

Add publisher confirms to know the broker actually accepted a published message. Use a dead-letter exchange (DLX) for messages that fail repeatedly — see RabbitMQ Exchanges, Queues, DLX, and Quorum Queues.

What it’s good for

  • Task queues / background jobs — distribute work to a pool of workers (Celery’s default broker — see What is Celery).
  • Complex routing — topic/headers exchanges fan one message out by rules.
  • Request/reply and per-consumer queues — work that’s consumed once, then gone.
  • Smoothing load spikes — the queue buffers bursts.

RabbitMQ vs Kafka

The interview’s favorite comparison. Different tools, not competitors.

RabbitMQ Kafka
Model smart broker, dumb consumer; routes & deletes on ack dumb broker, smart consumer; durable append-only log
After consumption message removed from queue message retained; offset advances
Replay no (it’s gone once acked) yes — rewind the offset
Routing rich (exchanges, bindings, wildcards) partitions by key; routing is the consumer’s job
Throughput high very high (designed for it)
Ordering per queue per partition
Best for task queues, complex routing, RPC event streaming, log/replay, high-volume pipelines

Rule of thumb: RabbitMQ when work is consumed once and routing matters; Kafka when you need a replayable event log at high throughput. See What is Kafka.

Common pitfalls

  • Forgetting idempotency — at-least-once delivery means duplicates; non-idempotent consumers double-process.
  • Auto-ack — acking on delivery (before processing) loses messages on a crash. Ack after success.
  • Durable queue but non-persistent messages (or vice versa) — both are required to survive a restart.
  • Unbounded prefetch — one greedy consumer grabs thousands of messages; set prefetch_count for fair dispatch.
  • No DLX — poison messages requeue forever in a hot loop. Route repeated failures to a dead-letter queue.
  • Treating it like Kafka — there’s no replay; once acked, a message is gone.

Interview angle 5

  • “What is RabbitMQ and how does routing work?” — an AMQP message broker; producers publish to exchanges, bindings route messages into queues by routing key/pattern, consumers ack them. Decouples producers from consumers.
  • “Exchange types?” — direct (exact key), topic (wildcard), fanout (broadcast), headers (match on headers). Topic is the common one.
  • “What delivery guarantee does it give?” — at-least-once with manual acks; duplicates are possible, so consumers must be idempotent. Durability needs durable queue + persistent message + manual ack together.
  • “RabbitMQ vs Kafka?” — RabbitMQ deletes messages after consumption and excels at routing/task queues; Kafka is a retained, replayable log built for high-throughput streaming. Pick by whether you need replay and volume vs flexible routing and once-only consumption.
  • “How do you handle a message that keeps failing?” — dead-letter exchange: after N failed attempts, route it to a DLQ for inspection/retry instead of requeueing it forever.