Vibe Engines
YouTube
System Design

Design a Message Queue

Step 1 / 9

Learn system design by building a distributed message queue like Kafka step by step.

The numbers to beatappend-onlywrite pathsequentialdisk I/Ooffsetmessage id

The whole design, in writing

Learn system design by building a distributed message queue like Kafka step by step. An interactive guide covering the append-only log, partitions, consumer groups and offsets, replication, leader election, retention, and delivery guarantees.

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

What is a message queue?

One service produces events much faster than another can handle them — or you want many services to react to the same event without the producer knowing they exist. Calling each consumer directly is brittle: a slow or dead consumer drags the producer down with it.

Producerspublish events
New in this step: Producers.

Put a durable log in the middle. Producers append; consumers read at their own speed. The producer fires and forgets; consumers come and go, replay history, and never block the producer. This one primitive underpins event-driven systems everywhere.

What the new pieces do

Producersproducer
Services that emit a firehose of events — clicks, orders, metrics — and want to hand them off and move on, without waiting for anyone to read them.

Step 1 · The core

An append-only log

A producer needs to hand off a message reliably, and a consumer needs to read messages in order, possibly long after they were written. A delete-on-read queue forgets too soon and can’t support replay or multiple readers.

Brokerappend + serveCommit Logappend-only
New in this step: Broker, Commit Log.

Consumers read in order long after a write, and multiple readers want the same stream. Model the topic as…

  1. Delete-on-read forgets too soon: no replay, and a second consumer can’t read what the first consumed. You lose history and multi-reader support.

  2. Random inserts/deletes mean index churn and locking, and you’d hand-roll ordering and cursors. A purpose-built log is far faster and simpler for an ordered stream.

  3. Writes only append (sequential disk I/O — shockingly fast), nothing is deleted on read, and order is implicit in the offset. Any number of consumers read it independently.

Model the topic as an append-only commit log: writes only ever append to the end and get a monotonically increasing offset. Nothing is deleted on read. Sequential disk appends are shockingly fast, and order is implicit in the offset.

  • append-onlywrite path
  • sequentialdisk I/O
  • offsetmessage id

What the new pieces do

Brokerbackend
The server that accepts writes from producers and serves reads to consumers. In a cluster, many brokers split the work; here we start with one.
Commit Loglog
The heart of it: an immutable, append-only sequence of messages on disk. Writes are just appends; each message gets a monotonically increasing offset.

Back of the envelope

append = sequential disk write
far faster than random I/O — near memory speeds
offset = position in the log
order is implicit, no extra index needed
reads don’t mutate
N consumers read one log independently

Step 2 · Beyond one disk

Partitions for parallelism

A single log is capped by one machine’s disk and CPU — both for write throughput and for how fast consumers can read. One ordered log can’t scale horizontally.

Brokerappend + servePartitionerkey → partitionPartition Logsappend-only
New in this step: Partitioner.

One ordered log is capped by a single machine’s disk and CPU. How do you scale throughput?

  1. Vertical scaling hits a ceiling and is still one machine — one disk’s write rate, one CPU’s read rate. You need to spread a topic across machines.

  2. Each partition is its own log on a possibly different broker; hashing a key keeps related events ordered together while unrelated events spread out. Throughput scales with partition count.

  3. Concurrent writers to one shared log destroy the cheap sequential-append property and reintroduce coordination. Order and speed both come from each partition having a single writer.

Split the topic into partitions, each its own log on a possibly different broker. A Partitioner routes each message — usually by hashing a key — so the same key always lands in the same partition. Throughput scales with partition count.

  • Npartitions = parallelism
  • key-hashrouting
  • per-partitionordering

What the new pieces do

Partitionerservice
Decides which partition an event lands in, usually by hashing a key. Same key → same partition → ordered together.

Back of the envelope

throughput ∝ partition count
add partitions to add parallelism
same key ⇒ same partition
related events stay ordered
order is per-partition only
not a global order across the topic

Step 3 · Many readers, no deletes

Consumer groups & offsets

If the log never deletes, how does a consumer know what it has and hasn’t read? And how do ten instances of a service share the work without each processing every message?

Consumer GroupBrokerPartition LogsOffsets
New in this step: Consumer Group, Offsets. · swipe to pan the diagram

The log never deletes. How do consumers track progress and share work without each reading everything?

  1. That’s back to a delete-on-read queue — no replay, and only one consumer can ever see a message. The log’s whole value is keeping data and letting readers track their own position.

  2. Re-scanning the whole log per consumer is hugely wasteful with no shared progress. You need a stored cursor, not a full re-read.

  3. Partitions are divided among a group’s members (processed once per group), and a server-side offset records position — so a crash resumes exactly where it left off and a rewind replays. Different groups read the same log independently.

Consumers join a group; the group’s partitions are divided among its members so each message is processed once per group. Each group tracks its position with an offset — a cursor stored by the broker. Different groups read the same log at totally different positions.

  • per-groupcursor
  • delivery / group
  • rewindto replay

What the new pieces do

Consumer Groupconsumer
Services that read the stream at their own pace — a fraud checker, a search indexer, a data warehouse — each independently, each possibly slow.
Offsetsstore
Where each consumer group has read up to. Stored server-side so a crashed consumer resumes exactly where it left off — the log itself is never mutated.

Step 4 · Don’t lose data

Replication

Partitions live on disks, and disks (and whole brokers) die. If a partition exists on only one broker, its death means permanent data loss and downtime for everyone reading or writing it.

Partition Logsappend-onlyReplicas (ISR)leader + followers
New in this step: Replicas (ISR).

A partition lives on a disk, and disks die. How do you not lose committed data?

  1. Backups are minutes stale, so a broker death still loses recent writes and downs that partition. Durability must be synchronous with the write, not a periodic snapshot.

  2. The leader takes reads/writes; in-sync replicas mirror it, and a write commits only once enough replicas have it (acks=all). Losing the leader loses nothing — an ISR is promoted.

  3. Replicating every partition to every broker wastes enormous disk and write bandwidth. A few copies (typically 3) survive failures — you don’t need a copy on all of them.

Replicate each partition across several brokers. One is the leader (takes all reads/writes); the others are in-sync replicas that mirror it. A write is “committed” once enough replicas have it, so losing the leader loses nothing.

  • ×3typical replication
  • acks=alldurable write
  • 0committed loss

What the new pieces do

Replicas (ISR)store
Each partition is copied to several brokers. One leader takes writes; in-sync followers mirror them, so a dead broker never loses committed data.

Back of the envelope

×3 replicas typical
survives 2 broker failures
acks=all ⇒ commit on ISR
durability you can trust, slight latency cost
0 committed loss
a promoted ISR already holds every committed write

Step 5 · When a broker dies

Leader election

A leader broker crashes mid-flight. Someone has to notice, promote a healthy in-sync replica to leader, and tell every producer and consumer where to go now — without two brokers both thinking they’re the leader.

Broker Clustermany brokersPartition Logsappend-onlyControllerleader election
New in this step: Controller.

The leader broker for a partition crashes mid-flight. How do clients keep working?

  1. Clients have no consistent global view and could split-brain — two brokers each believing they lead. Leadership must be decided by one authority, not negotiated by clients.

  2. The controller watches health and promotes an in-sync replica via consensus (ZooKeeper/KRaft), then propagates metadata so clients transparently reconnect. Consensus is needed only for who-leads, not every message.

  3. Freezing the partition until a human fixes a machine destroys availability. The point of replication is to fail over in seconds, not wait for repair.

A Controller watches broker health and runs leader election over a consensus store (ZooKeeper, or Kafka’s own KRaft). It promotes an in-sync replica and propagates the new metadata, so clients transparently reconnect to the new leader.

What the new pieces do

Controllerservice
Tracks which brokers are alive and elects a new partition leader when one dies. Backed by a consensus store (ZooKeeper, or KRaft today).

Step 6 · The log can’t grow forever

Retention & compaction

An append-only log that never forgets eventually fills every disk. But you also can’t blindly delete — some consumers replay history, and some topics need the latest value per key kept indefinitely.

Partitionerkey → partitionPartition Logsappend-onlyReplicas (ISR)leader + followersRetentiontime / size
New in this step: Retention.

Apply a retention policy: drop log segments older than N days or beyond a size cap. For keyed topics, use log compaction to keep only the most recent message per key, so the log becomes a compact snapshot of current state.

What the new pieces do

Retentionpolicy
The log can’t grow forever. Old segments are dropped by age or size — or compacted to keep only the latest value per key.

Step 7 · What can it promise?

Delivery guarantees

Networks drop acks and clients crash mid-batch, so producers retry and consumers reprocess — producing duplicates. Applications need to know what the system actually guarantees.

ProducersConsumer GroupBroker ClusterPartitionerPartition LogsReplicas (ISR)OffsetsControllerRetention
The system as it stands at this step. · swipe to pan the diagram

Retries and crashes cause reprocessing. What guarantee do you offer, and how do you avoid duplicates?

  1. Not retrying gives at-most-once — dropped messages on any failure. You can’t get reliability by giving up delivery; exactly-once is built on top of at-least-once, not instead of it.

  2. Committing first means a crash after the commit but before the work silently loses the message (at-most-once). The safe default is to commit after processing.

  3. Retry until acked (accepting dupes), then dedup by producer-id + sequence and use transactions to commit write+offset atomically. Consumers commit offsets only after processing — that ordering defines the guarantee.

Default to at-least-once: retry until acknowledged, accept possible duplicates. Layer idempotent producers (dedup by producer id + sequence) and transactions (atomic write-plus-offset-commit) to reach exactly-once within Kafka. Consumers commit offsets only after successfully processing.

You did it

You just designed a message queue.

ProducersConsumer GroupBroker ClusterPartitionerPartition LogsReplicas (ISR)OffsetsControllerRetention
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • An append-only commit log — ordered, immutable, replayable.
  • Partitions split the log across brokers; a key-hash keeps order per partition.
  • Consumer groups + server-side offsets: read once per group, rewind to replay.
  • Replication with a leader + in-sync replicas so no committed write is lost.
  • A controller runs leader election over a consensus store on broker failure.
  • Retention and compaction keep the log from growing without bound.
  • At-least-once by default; idempotent producers + transactions for exactly-once.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. Why is Kafka so fast despite writing to disk?

    Sequential appends + the OS page cache + zero-copy (sendfile) reads. Appending to the end of a file is sequential I/O, which modern disks handle at near-memory throughput, and consumers are often served straight from page cache without copying through user space. The log structure unlocks all of it.

  2. How many partitions should a topic have?

    Enough for your peak parallelism (a partition is the unit of both consumer concurrency and ordering), but not so many that controller metadata, open files and end-to-end latency balloon. You can add partitions later, but it breaks key→partition stability — so size with headroom up front.

  3. What’s the trade-off in choosing a partition key?

    The key controls both ordering and load balance. Too coarse (e.g. country) creates hot partitions; too fine loses the ordering you wanted. Pick the entity whose events must stay ordered (user id, order id) and whose cardinality spreads load evenly.

  4. Does exactly-once work end-to-end, including external sinks?

    Within Kafka, yes — idempotent producers + transactions give exactly-once for read-process-write between topics. To an external system (a database, an email) it’s only exactly-once if that sink is idempotent or joins the transaction; otherwise you fall back to at-least-once + idempotent writes downstream.

  5. A consumer group is slow — what happens to the cluster?

    Nothing upstream: producers keep appending and other groups read normally. The slow group’s lag (latest − committed offset) grows; if it can’t catch up before retention drops old segments, it loses those messages. You monitor consumer lag and scale the group out, up to the partition count.

Check yourself — the answers, and why

Eight steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. The core data structure of a queue like Kafka is…

    • A priority queue
    • An append-only commit log
    • A hash table

    Ordered, immutable, replayable — reads don’t mutate it, so many consumers share it.

  2. Ordering in Kafka is guaranteed…

    • Across the whole topic
    • Within a single partition
    • Per consumer

    Partitions parallelize; a good key keeps related events in one partition, hence ordered.

  3. A crashed consumer resumes correctly because…

    • Messages are re-sent
    • Its offset cursor is stored server-side
    • The log is locked

    Reading is just advancing an offset; restart resumes from the last committed position.

  4. "acks=all" means a write is acknowledged…

    • After the leader writes it
    • After the in-sync replicas have it
    • After consumers read it

    Committing only after replication means losing the leader loses no committed data.

  5. Kafka’s default delivery guarantee is…

    • At-most-once
    • At-least-once (exactly-once with idempotence + transactions)
    • Exactly-once always

    Retry-until-acked yields duplicates; idempotent producers + transactions layer exactly-once on top.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Publish + subscribe: producers append events; consumers read the stream at their own pace, replaying history.
  • Partition: split a topic into partitions routed by key hash — same key, same partition, ordered.
  • Track progress: consumer groups split partitions; a server-side offset lets a crash resume and a rewind replay.
  • Durability: replicate each partition (leader + in-sync replicas); commit only after replication.
  • Survive + bound: a controller elects a new leader on failure; retention/compaction cap the log; at-least-once by default.

The qualities that shape everything

Each one names the mechanism that buys it.

Decouple a fast producer from slow or dead consumers
A durable append-only log in the middle — producers append and move on; consumers read at their own speed, and a dead consumer just stops advancing its offset.
Scale throughput past one machine
Split the topic into partitions on different brokers, routed by key hash so same-key events stay ordered while unrelated events spread.
Read once per group, and rewind to replay
Consumer groups divide partitions among members and a server-side offset records position, so a crash resumes exactly and a rewind replays.
No committed write lost when a broker dies
Replicate each partition to a leader plus in-sync replicas and commit only after acks=all, so a promoted ISR already holds every committed write.
Fail over in seconds without split-brain
A Controller runs leader election over a consensus store (ZooKeeper/KRaft) and propagates metadata so clients transparently reconnect.
A delivery guarantee apps can build on
At-least-once by default (retry until acked); idempotent producers + transactions layer exactly-once on top.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

An append-only commit log over a delete-on-read queue

Delete-on-read forgets too soon — no replay, and a second consumer can’t read what the first consumed; an append-only log keeps history and lets any number of consumers read independently.

Partitions routed by key hash over a bigger single broker

Vertical scaling hits one disk’s write rate and one CPU’s read rate; splitting a topic into partitions on many brokers scales throughput while a key-hash keeps related events ordered.

Consumer groups + server-side offsets over the broker pushing and deleting each message

Push-and-delete is back to a queue only one consumer can read with no replay; a stored offset cursor lets groups read the same log independently and rewind to replay.

Leader + in-sync replicas (acks=all) over periodic backups to cold storage

Backups are minutes stale, so a broker death still loses recent writes; committing only after in-sync replicas have the write means losing the leader loses nothing.

Controller-run leader election over clients electing a leader among themselves

Clients have no consistent global view and could split-brain; a controller promotes an in-sync replica via consensus — consensus is needed only for who-leads, not every message.

What this teaches

Learn system design by building a distributed message queue like Kafka step by step. An interactive guide covering the append-only log, partitions, consumer groups and offsets, replication, leader election, retention, and delivery guarantees.

Key takeaways

  • An append-only commit log — ordered, immutable, replayable.
  • Partitions split the log across brokers; a key-hash keeps order per partition.
  • Consumer groups + server-side offsets: read once per group, rewind to replay.
  • Replication with a leader + in-sync replicas so no committed write is lost.
  • A controller runs leader election over a consensus store on broker failure.
  • Retention and compaction keep the log from growing without bound.
  • At-least-once by default; idempotent producers + transactions for exactly-once.

Concepts covered

  • What is a message queue?
  • An append-only log
  • Partitions for parallelism
  • Consumer groups & offsets
  • Replication
  • Leader election
  • Retention & compaction
  • Delivery guarantees
built to be replayed, not memorized — make the calls, kill the leader, run the gauntlet.
Finished this one? 0 / 65 System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More System Designs