Design a Distributed Message Queue (Kafka-style)

The log-based queue interview: topics split into partitions for parallelism, an append-only offset log, consumer groups, replication with ISR, and where ordering and exactly-once actually hold.

system-designkafkamessagingcase-study

Prompt

Design a durable, scalable message queue (think Kafka / Kinesis): producers publish, consumers read, messages survive broker crashes, throughput scales horizontally, and consumers can replay. What are the ordering and delivery guarantees?

Why this one, and at what level

It ties together replication, partitioning, and delivery semantics — and underpins background jobs, event aggregation, and Kafka the tool. SDE-1: producer/consumer + durability. SDE-2: partitions, consumer groups, and ordering. SDE-3 / Staff: replication/ISR, delivery semantics, and exactly-once. Asked at Confluent, Amazon, Uber, LinkedIn, Stripe.

1. The core abstraction — an append-only log

A topic is an append-only log split into partitions. Each message gets a monotonically increasing offset within its partition. Consumers track their own offset and read forward; nothing is deleted on read (unlike SQS) — messages persist for a retention period, which is what makes replay possible.

topic "clicks", partition 0:  [m0][m1][m2][m3][m4...]   ← producers append at the tail
                                              ▲
                          consumer A offset ──┘  (reads forward, commits its offset)

2. Partitions = parallelism + ordering

The partition is the unit of both scale and order:

  • Parallelism: N partitions ⇒ up to N consumers in a group read in parallel. To scale throughput, add partitions.
  • Ordering — only within a partition. There is no global order across partitions. To keep related messages ordered (all events for one user), key them so they hash to the same partition. This is the most common ordering gotcha.

3. Consumer groups

A consumer group splits a topic's partitions across its members — each partition is consumed by exactly one consumer in the group, so work is divided without duplication. Add consumers to scale (up to the partition count); if one dies, its partitions rebalance to the others. Different groups read the same topic independently (each at its own offset) — that's how one stream fans out to many subscribers.

4. Replication & durability

Each partition is replicated to several brokers: one leader handles reads/writes, the followers replicate it. The set of replicas caught up to the leader is the ISR (in-sync replicas). A write is acknowledged once enough replicas have it (acks=all ⇒ all ISR), so the data survives a broker loss; if the leader dies, an ISR member is promoted. The acks setting is the durability vs latency dial.

5. Delivery semantics

  • At-most-once: commit offset before processing — fast, can lose messages.
  • At-least-once (default): process, then commit — a crash in between causes redelivery, so consumers must be idempotent (see background jobs).
  • Exactly-once: achievable within the system via an idempotent producer (dedupes retries) + transactional writes (atomic produce + offset commit). End-to-end, it still relies on idempotent side effects.

Brokers are typically pull-based (consumers fetch at their own pace), which gives natural backpressure — a slow consumer just falls behind (rising consumer lag) instead of being overwhelmed.

Design drills

Design drills: Distributed Message Queue0/3 done

Whiteboard each one out loud for 5–10 minutes before you reveal what a strong answer covers — the gap between your sketch and the checklist is your study list. Progress is saved on this device.

Core

Guarantee all events for a given user are processed in order, while still scaling throughput.

Stretch

A broker holding a partition leader crashes. Don't lose acknowledged messages.

Stretch

Achieve effectively exactly-once processing despite at-least-once delivery.