How Message Queues Work

Intermediate
8 min read· Backend & Databases

A message queue is a buffer that sits between two services, letting them communicate without being directly connected or even running at the same time. Instead of Service A calling Service B directly (tight coupling), A drops a message into the queue and moves on. B reads the message when it's ready. This pattern is the backbone of every large-scale distributed system — it enables decoupling, async processing, load smoothing, and fault tolerance all at once.

Think of it like a restaurant order system

When a waiter takes your order, they don't stand next to the chef waiting for the food — they write the order on a ticket and pin it to the board (the queue). The chef picks tickets up when ready, cooks at their own pace, and the waiter serves other customers in the meantime. Neither the waiter nor chef needs to know what the other is doing. If the kitchen is slammed, tickets pile up but nothing is lost.

Step by Step

1 / 6

Key Concepts

Topic

In Kafka, a topic is a named, ordered, append-only log of messages. Producers write to topics. Consumers read from topics. A topic can have multiple partitions for parallelism. Examples: "order-created", "payment-processed", "email-notifications".

Partition

A topic is split into partitions — independent ordered logs distributed across broker nodes. Messages with the same key always go to the same partition, preserving order for that key. More partitions = more parallelism.

Consumer Group

A set of consumers that collectively consume a topic. Each partition is assigned to exactly one consumer in the group. If a consumer dies, its partitions are rebalanced to other consumers in the group. Different groups each get all messages independently.

Offset

Kafka's unique message identifier within a partition. The consumer tracks which offset it has processed. Committing an offset tells Kafka the consumer has successfully processed up to that point. Consumers can seek to any offset to replay history.

Exchange (RabbitMQ)

The component that receives messages from producers and routes them to queues based on routing rules. Types: direct (exact routing key match), topic (wildcard match), fanout (broadcast to all bound queues), headers.

Acknowledgement (ACK)

A signal from the consumer to the broker confirming successful message processing. Without ACK, the broker will redeliver the message after a timeout. ACKing too early (before processing) risks data loss; ACKing too late holds up resources.

Dead Letter Queue (DLQ)

A queue where messages go after exceeding their retry limit. Prevents poison pill messages (malformed data that always fails) from blocking a queue forever. Essential for operational visibility into failures.

Idempotency

Processing the same message multiple times produces the same result. Critical with at-least-once delivery — your consumer might receive duplicates. Design consumers to be idempotent: use a unique message ID to detect and skip already-processed messages.

Key Facts

  • Apache Kafka was originally built at LinkedIn to process activity stream data. It now processes over 7 trillion messages per day at LinkedIn alone.
  • Kafka retains messages on disk for days or weeks by default — this means any consumer can replay history, unlike traditional queues that delete messages after delivery.
  • RabbitMQ routes messages in microseconds and excels at complex routing scenarios. Kafka excels at high-throughput event streaming and replay.
  • At-least-once delivery (the default) means your consumer may see duplicate messages. Kafka also supports exactly-once semantics (EOS) using idempotent producers and transactional APIs.
  • Kafka's throughput is measured in millions of messages per second per cluster — it achieves this by batching messages, sequential disk writes, and zero-copy I/O.
  • The producer-consumer pattern in message queues is directly related to the producer-consumer concurrency pattern in operating systems and concurrent programming.

Real-World Applications

Order processing pipelines

An e-commerce platform publishes an "order-placed" event to Kafka. Multiple consumers independently react: inventory service reserves stock, payment service charges the card, email service sends a confirmation. If any step fails, it retries independently without affecting the others.

Decoupling microservices

Instead of Service A making a synchronous HTTP call to Service B (which fails if B is down), A publishes an event. B consumes it when ready. Services can be deployed, restarted, and scaled independently. This is the foundation of event-driven microservices architecture.

Log aggregation

Every application instance publishes logs as Kafka messages. A single consumer pipeline reads all logs, enriches them, and writes to Elasticsearch for searching. This scales to billions of log entries per day without overwhelming the log storage system.

Background job processing

Instead of processing a video upload synchronously (making the user wait), the API publishes a "video-uploaded" message and returns immediately. A background worker consumes the message, transcodes the video, and notifies the user when done.

Frequently Asked Questions

When should I use Kafka vs RabbitMQ?

Use Kafka when you need high throughput (millions of events/sec), message replay/history, or an event log that multiple independent consumers can read. Use RabbitMQ when you need complex routing logic, request/reply patterns, or lower-latency delivery for task queues. RabbitMQ is easier to operate; Kafka requires more infrastructure expertise.

How do I handle duplicate messages?

Design your consumers to be idempotent. Store a processed_message_ids table in your database and skip messages whose ID has already been processed. For financial transactions, use a unique transaction ID in both the message and the database upsert to prevent double charges.

What is the difference between a queue and a topic?

A queue (RabbitMQ-style) delivers each message to exactly one consumer — it's for work distribution. A topic (Kafka-style or pub/sub) delivers each message to all subscribers independently — it's for event broadcasting. Kafka consumer groups give you both: multiple consumers sharing work, but different groups each seeing all messages.

How does a message queue improve system reliability?

Without a queue, if Service B is down when A tries to call it, the request fails and data is lost. With a queue, the message is stored durably and B processes it when it recovers. The queue also acts as a buffer during traffic spikes — messages accumulate safely instead of overwhelming B with more requests than it can handle.

Related Topics