Distributed Message Queue Interview Questions | JiQuest

add

#

Distributed Message Queue

System design deep dive · HLD

Design a Distributed Message Queue (Kafka-like event log): full high-level design.

Requirements, back-of-envelope capacity estimation, a high-level component diagram, a deeper deployment architecture diagram with partitions and replicas spread across brokers, sequence diagrams for the produce-with-acks and consume-with-offset-commit paths, and an entity-relationship diagram for the cluster metadata model - with the reasoning an interviewer expects behind every box and arrow.

2M/secMessages ingested
3xReplication factor
7 daysDefault retention
Producerkey=user-42 Partition 3 · leaderappend log, offset 118423 Follower replicabroker-7, in-sync acks=all ✓ISR quorum, durable Consumer grouppolls from offset 118400 ack returns to producer

1. Clarify requirements before drawing any box

A strong system design answer starts by pinning down scope out loud. For a Kafka-like distributed message queue, that means separating what the system must guarantee from how fast it must go, and being explicit that ordering and delivery guarantees are scoped to a partition, not the whole topic.

Functional requirements

Append to topicsProducers append messages/events to named topics; each topic is split into partitions for parallelism.
Ordered per-partition readConsumers, organized into consumer groups, read messages in order within a partition and track their own offset.
At-least-once deliveryA committed message is always eventually delivered; duplicates on reprocessing are acceptable by default.
Time-based retentionMessages are retained for a configurable window and are not deleted on consume, unlike a traditional queue.

Non-functional requirements

Very high write throughputAppend-only sequential disk writes so a single broker can sustain tens of MB/sec per partition.
DurabilityReplication guarantees no committed message is ever lost, even if a broker dies mid-flight.
Bounded orderingOrdering is guaranteed only within a partition, never across an entire topic.
Horizontal scalability + replayScale out by adding partitions/brokers; consumers can rewind and replay from any earlier offset.
Explicitly out of scope Exactly-once semantics as the default mode, a schema registry / data-governance layer, and active-active cross-datacenter geo-replication are called out as extensions in the deep-dive section rather than core requirements, so the core design stays focused on partitioning, replication, and offsets.

2. Back-of-the-envelope capacity estimation

These numbers decide everything downstream: how many partitions the cluster needs at minimum, how many brokers are required to absorb replicated write I/O, and how much disk the retention window actually costs.

MetricAssumptionResulting estimate
Average ingest2,000,000 messages/sec across all topics, ~1 KB average message size2,000,000 × 1KB ≈ 2 GB/sec average write throughput
Peak ingest~3× average during traffic spikes≈ 6 GB/sec peak write throughput
Minimum partition counta single partition tops out around 15 MB/sec of sequential disk write on typical disks2 GB/sec ÷ 15 MB/sec ≈ 134 partitions minimum, provisioned generously to ≈ 5,000 partitions across ≈ 800 topics for consumer parallelism headroom
Replication factorRF = 3 (1 leader + 2 followers) for durabilitywrite I/O triples cluster-wide: 2 GB/sec logical → ≈ 6 GB/sec of physical disk writes
Brokers neededeach broker sustains ≈ 250 MB/sec durable sequential write across its disks6 GB/sec ÷ 250 MB/sec ≈ 24 brokers minimum, provisioned to ≈ 150 brokers across 3 AZs for headroom and rack spread
Retention storage7-day retention window, RF = 32 GB/sec × 604,800 sec × 3 ≈ 3.6 PB of hot storage cluster-wide
Why this matters The 15 MB/sec-per-partition ceiling is the single number that forces horizontal partitioning at this scale - there is no vertical-scaling escape hatch, because a partition is an ordered log that can only be appended to by one leader at a time. Everything else (broker count, replica placement, tiered storage) exists to serve that constraint.

3. High-level design (HLD)

The HLD names the major components and the one-directional data flow between them, without committing yet to specific broker counts, racks, or regions - that level of detail belongs in the architecture diagram in the next section.

Producerskey-based writes Partitionerhash(key) % N Partition leaderappend (write path) Consumer grouppoll (read path) ControllerRaft/KRaft quorum Follower replicasin-sync set (ISR) Append-only logsequential disk Offset store__consumer_offsets Retention / GCcompaction, expiry
Producer/consumer pathsControl plane & replicationDurable storageAsync background

What each box owns

Producers & the partitioner

Producers batch and compress messages client-side, then a partitioner hashes each message's key to pick a partition (or round-robins for keyless messages). The key choice determines both throughput distribution (a hot key skews load to one partition) and ordering guarantees (only messages sharing a key are guaranteed relative order).

Broker cluster: partition leaders and follower replicas

Every partition has exactly one leader broker at a time; all produces and consumes for that partition go through the leader. Follower brokers replicate the leader's log and can be promoted to leader instantly if the leader dies, which is why replicas are always placed on different brokers/racks than the leader.

Controller / metadata layer

A small quorum (a Raft-based controller, e.g. KRaft, or an external coordination service like ZooKeeper in older designs) tracks which broker leads which partition and which brokers are alive, and triggers leader election the moment a leader broker stops heartbeating.

Consumer groups, offset store & retention

Within a consumer group, each partition is consumed by exactly one member, so offset bookkeeping is a simple per-partition counter. Committed offsets live in a durable offset store (itself often a compacted internal topic). A background retention/compaction process reclaims disk by deleting segments older than the retention window or by compacting away superseded values per key.

4. Detailed architecture diagram

The architecture diagram takes every HLD box and answers "how is this actually deployed?" - replica placement across availability zones, the controller quorum, tiered storage, and how a consumer group's instance count maps onto partition count, which is what an interviewer is checking for once they've accepted the high-level shape.

Producer edge layer Producer SDKbatches + compresses Bootstrap serversbroker metadata Partitionerhash(key) % partitions Schema registryAvro / Protobuf compat Availability zone A - partition leaders Partition 3 leader · broker-12 Partition 7 leader · broker-14 Local NVMe log segments Page cachefsync on flush.ms Availability zones B/C - followers + controller Partition 3 followerbroker-27 (ISR) Partition 7 followerbroker-31 (ISR) Controller quorum ×3KRaft / Raft consensustracks leadership +broker liveness Tiered storage Hot segmentslast 24h, local disk Warm segments24h - 7 days cold segments (>7d) offloaded to S3/GCS Retention & compaction Time-based GCdeletes segments past retention_ms log compaction: keep latest value per key Consumer group: order-events 6 consumer instances P0-P4 → 5 consumers, 1 idle
DecisionChoiceReasoning
Partition count vs consumer parallelismPartitions provisioned above current consumer count (e.g. 6 for order-events)Partition count is a hard ceiling on parallelism within a group - more consumers than partitions leaves the extras permanently idle, so partition count must be sized for future consumer growth up front.
Replication modeSync replication with an in-sync-replica (ISR) quorum (acks=all)The leader only reports a message committed once every ISR member confirms it, which is higher latency but guarantees zero loss even if the leader dies immediately after; async replication (acks=1) is faster but risks losing the last few messages on a leader crash.
Retention policyTime-based deletion by default, log compaction on select topicsEvent-stream topics need every event (time-based retention); changelog/state topics only need the latest value per key forever (log compaction) - mixing them wrong either wastes disk or silently drops history that was needed.

5. Sequence diagrams for the two critical flows

A sequence diagram is where an interviewer checks whether you actually understand call order, which acknowledgment level is being waited on, and what happens on failure between the two.

5.1 Producer publish with acks=all (write path)

Producer Partition leader Follower A (ISR) Follower B (ISR) 1. Produce(topic, key=user-42, acks=all) 2. append to local log, assign offset 118423 3. replicate offset 118423 4. replicate offset 118423 5. fetch ack (caught up) 6. fetch ack (caught up) 7. ISR quorum satisfied → commit point advances 8. Ack: offset=118423 committed

Steps 3 and 4 fire in parallel and the leader waits for the slowest ISR member before step 7 - that wait is the entire cost of durability. With acks=1 the leader would return the ack right after step 2, skipping 3-7 entirely and trading durability for lower latency; with acks=0 it would not even wait for step 2's local append to be flushed.

5.2 Consumer poll and offset commit (read path)

Consumer Partition leader Offset store Coordinator 1. Fetch(partition=3, offset=118400) 2. batch [118400..118422] 3. process batch (business logic) 4. commit offset=118423 5. ack 6. heartbeat (session alive) if crash occurs between 3 and 4: offset stays at 118400 next poll re-fetches [118400..] → reprocessed (at-least-once)

Committing the offset only after the batch is fully processed (step 4, after step 3) is what makes delivery at-least-once rather than at-most-once: if the consumer crashes between steps 3 and 4, the committed offset never advances past 118400, so the next poll - by this consumer restarting or by a rebalanced peer - re-fetches and reprocesses the same batch. That is a deliberate trade-off, not a bug: it guarantees no message is silently skipped, at the cost of possible duplicate processing that the consumer's own logic must tolerate.

6. Entity-relationship (ER) diagram and metadata model

This ER diagram models cluster metadata, not the messages themselves - the actual message log lives in purpose-built append-only segment files on disk, never in a database. Metadata has to answer: which partitions belong to which topic, who leads each partition, and where each consumer group currently is per partition.

topics PK topic_id BIGINT UQ name VARCHAR partition_count BIGINT replication_fct BIGINT retention_ms BIGINT created_at TIMESTAMP partitions PK partition_id BIGINT FK topic_id BIGINT partition_number INT leader_broker_id BIGINT log_start_offset BIGINT log_end_offset BIGINT isr_broker_ids ARRAY updated_at TIMESTAMP consumer_offsets PK id BIGINT group_id VARCHAR FK partition_id BIGINT committed_offset BIGINT committed_at TIMESTAMP 1N 1N one topic has many partitions; one partition has one consumer_offsets row per consumer group tracking it

Key modeling decisions

partition_id is a surrogate keyconsumer_offsets references a single BIGINT rather than a composite (topic_id, partition_number), keeping the offset commit path a single-column lookup.
consumer_offsets is itself a compacted topic in productionReal Kafka stores committed offsets in the internal __consumer_offsets topic, keyed by (group, topic, partition), log-compacted to keep only the latest offset per key - not a relational table at all.
log_start_offset advances independently of log_end_offsetRetention/compaction deletes old segments, advancing log_start_offset, while log_end_offset only moves forward on new appends - offset is a position, not a message count.
Metadata is tiny compared to the data it describesA few KB per partition versus petabytes of message data, which is exactly why metadata can live in a strongly consistent quorum while the log itself cannot.
Storage choiceUse whenWatch out for
Message log (topic/partition data)Purpose-built append-only segment files (Kafka's own log format), never a general-purpose database.Optimized purely for sequential append and offset-indexed sequential read; a relational engine's transactions and random-I/O indexes would only add overhead the log doesn't need.
Cluster & topic metadataSmall enough to live in a Raft-based coordination quorum (KRaft) or even a relational store.Needs strong consistency and fast propagation - a stale leader pointer sends producers/consumers to the wrong broker until the metadata catches up.

7. Deep dives interviewers actually probe

Why is a partition the unit of both parallelism and ordering?

A partition is a single ordered, append-only log with exactly one leader broker, so it is both the smallest unit that can be written/read in parallel (more partitions = more concurrent leaders = more throughput) and the largest unit within which ordering is guaranteed (Kafka never guarantees order across partitions). A producer's partitioning key choice sits directly on this trade-off: sending every message for a given entity (e.g. a specific user's events) to the same key guarantees they land in the same partition and are read in order, but if that key is unusually hot it also concentrates load onto one partition's leader, capping that entity's throughput at a single partition's ceiling.

// Typical client-side partitioner
int partitionFor(String key, int numPartitions) {
    int hash = murmur2(key.getBytes(UTF_8));
    return Math.abs(hash) % numPartitions; // same key -> same partition, always
}

What does acks=0 / acks=1 / acks=all actually trade off?

These are the durability/latency knob on the write path. acks=0: producer never waits for any response, sub-millisecond latency, but a message is silently lost if it never even reaches the leader's socket buffer. acks=1: producer waits only for the leader's local append (roughly 1-2ms), but if the leader crashes microseconds after acking - before any follower replicated it - the message is gone even though the producer believes it succeeded. acks=all: producer waits for every in-sync replica (ISR) to confirm (roughly 5-10ms under normal replication lag), and the message survives as long as at least one ISR member survives the failure - this is the only setting that satisfies the "no committed message is ever lost" requirement.

What happens during consumer group rebalancing?

When a consumer joins or leaves a group (deploy, crash, scale-out), the group coordinator must reassign partitions among the surviving members. The classic "stop-the-world" rebalance pauses every consumer in the group - even ones whose partition assignment doesn't change - for the duration of reassignment, which can be seconds on a large group and directly stalls consumption. Incremental cooperative rebalancing instead only revokes the specific partitions that actually need to move to a different consumer, letting unaffected members keep consuming throughout - it trades a more complex two-phase protocol for a much shorter pause window, which matters a lot at high partition/consumer counts.

Why is at-least-once the default, and what would exactly-once cost?

At-least-once falls out naturally from committing the offset after processing (see the crash scenario in the consume sequence diagram above): a crash between processing and committing causes safe reprocessing rather than silent loss, which is the cheaper failure mode to default to. True exactly-once requires two additional mechanisms working together: an idempotent producer (each message carries a producer ID + monotonic sequence number so the broker can drop exact duplicates from retries) and a transactional write that atomically spans both the log append and the offset commit, so a consumer-then-produce chain either fully commits or fully rolls back as one unit. That coordination overhead (extra round trips, transaction markers written to the log) measurably lowers throughput, which is why most high-volume pipelines accept at-least-once plus an idempotent consumer instead of paying for exactly-once everywhere.

What is the single biggest bottleneck as this scales 10x?

Not a single broker's disk in isolation - that's solved by adding partitions and brokers per the capacity math above. At 10x scale (tens of thousands of partitions cluster-wide) the real bottleneck shifts to the controller: every leadership change, broker join/leave, or partition creation must propagate to every broker's metadata cache, and with an external coordination service this metadata-propagation latency grows with partition count, causing slow leader elections and stale-metadata errors during incidents. The two levers that address this are tiered storage (offloading cold segments to object storage so local disk pressure stops scaling with retention window, addressing the I/O side) and moving the controller onto a built-in Raft-based consensus layer (KRaft-style) instead of an external coordination service, which shrinks the metadata footprint and cuts propagation latency at high partition counts.

8. Summary: what a strong answer covers

Scoped ordering to a single partition, not the topicJustified partition and broker counts with mathSeparated the durability knob (acks) from throughput Explained at-least-once vs. exactly-once cost honestlyKept metadata storage distinct from the message logDiscussed rebalancing trade-offs, not just the happy path
Interview tip The strongest signal in a message queue design interview is treating the partition as the fundamental unit of the whole system: parallelism, ordering, replica placement, and consumer assignment all derive directly from partition count, so justify that number explicitly with the math rather than treating it as an afterthought.
No comments
Leave a Comment