skip to content

If three different services (billing, shipping, and analytics) all need to react to the same 'OrderPlaced' notification, how does supporting that differ structurally between a destructive-read queue like RabbitMQ and an append-only log like Kafka?

level: middleimportance: should knowfreq 60%

answer

  1. N queues vs N consumer groups
  2. fan-out exchange / SNS
  3. storage duplicated per queue vs stored once
  4. new consumer = broker config vs client-side offset
  5. retention window still applies per log

basics

~20 s

With a queue, you need three separate queues (or a fan-out router) so each service gets its own copy, because one message can only be taken once. With a log, all three can just read the same shared stream independently, each keeping its own place.

solid answer

~40 s

A single RabbitMQ or SQS queue delivers each message to exactly one consumer, so broadcasting to three services requires an explicit fan-out layer - e.g., a RabbitMQ exchange bound to three queues, or SNS fan-out to three SQS queues - meaning N services means N physical queues, each with independent depth, retries, and DLQs. A Kafka topic is inherently multi-reader: each service runs its own consumer group with its own offset on the same partitions, so adding a fourth service later just means creating a fourth consumer group - no change to the producer or existing consumers, and no duplication of storage per consumer.

go deeper

for a junior

Should know queues generally deliver one copy per queue while logs allow multiple independent readers of the same stream.

for a middle

Should describe the concrete fan-out mechanism (exchange bindings / SNS-to-SQS) versus consumer groups, and know storage is duplicated in the former.

for a senior

Should weigh the operational trade-offs (isolation and per-consumer backpressure in queues vs zero-friction extensibility but shared retention risk in logs) for a given system.

for a principal

Should design around this distinction proactively - e.g., choosing a log specifically to keep the door open for unknown future consumers, or explaining when queue-per-consumer isolation is worth the extra ops cost.

## Broadcasting with queues In RabbitMQ, a producer publishes to an exchange, and the exchange's type (fanout, topic, etc.) determines which bound queues receive a copy of the message; in AWS, the equivalent is SNS fan-out, where one SNS topic publishes to N subscribed SQS queues. Either way, broadcasting to three services means provisioning three physical queues, each with its own retry settings, visibility timeouts, and dead-letter queue, and the message is physically duplicated once per queue until each is acked. ## Broadcasting with a log In Kafka, a topic's partitions are read non-destructively, so the broker only needs to track per-consumer-group offsets on top of the single stored copy of each message. Adding a fourth consumer group costs zero additional storage beyond the topic's retention and requires no broker reconfiguration or producer awareness - it's a purely client-side action of creating a new group and starting to poll. ## What each was built around This difference traces back to what each technology was built around. - **Queues** were designed for the 'competing consumers' pattern: many workers pulling from ONE queue to share load, where adding a worker to the SAME queue splits the work rather than duplicating it - broadcasting to independent services is a bolt-on pattern requiring extra plumbing. - **Logs** were designed around 'publish once, many independent subscribers': broadcast-to-N is the default behavior, and load-sharing within a single logical consumer is instead achieved by splitting a topic into partitions and running multiple instances inside one consumer group. ## The trade-offs The trade-offs run in opposite directions. - **Queue-based fan-out** gives strong isolation: a spike or outage in the analytics queue can't affect billing's queue depth, each consumer can tune its own retry/backoff independently, and per-consumer dead-lettering is trivial - but it costs more upfront design, since adding a new consumer means someone has to provision a new queue and binding, and it costs more storage since the message is physically duplicated N times. - **Log-based fan-out** gives effortless extensibility - spin up a new consumer group anytime, even against history - and stores the message once, but the broker provides no automatic backpressure isolation between consumer groups: a paused or slow group just accumulates lag rather than being isolated the way a separate queue would be, and all groups share the same retention clock on the underlying data. ## Failure modes Failure modes differ correspondingly. - **On the queue side**, forgetting to bind a new queue to the exchange means that service silently receives nothing - a routing configuration bug rather than a data bug, since the exchange has no concept of an unknown subscriber. - **On the log side**, the risk is a consumer group being paused (e.g., for a deploy or incident) longer than the topic's retention window: unlike a queue where unacked messages sit indefinitely, a stalled Kafka consumer group can silently lose access to the oldest events once they age out of retention, with no alert unless someone monitors lag against the retention window specifically. ## The same latecomer, both ways A concrete scenario: - **With RabbitMQ**, engineering sets up a topic exchange named `orders` with bindings to `billing.orders` and `shipping.orders`; when analytics later needs the data, a new `analytics.orders` queue and binding must be created, and analytics only sees orders placed after that binding exists - nothing historical is recoverable from the exchange. - **With Kafka**, an `orders` topic retains 30 days of data; when the analytics team joins six months later, they create a new consumer group and can choose to start from the earliest offset still within that 30-day window or from 'now,' with no coordination needed with the producer or any other consumer group.

  • Why doesn't adding a fourth consumer group to an existing Kafka topic require any change to the producer or existing consumers?
    Because the broker only stores messages once per partition and tracks offsets per consumer group independently; a new group is purely metadata (a new offset entry) created client-side on first poll, with zero impact on the topic's data or on how other groups read it.
  • In the RabbitMQ fanout-exchange pattern, what happens to a service that is added after the exchange and bindings were already created and running for a while?
    It only starts receiving messages published after its queue binding is created; it gets nothing from before that point, since the exchange doesn't retain history - unlike a log, there's no way to backfill except by replaying from the original producer or another durable store.
  • Does using a Kafka consumer group for load-sharing (competing-consumers-style, multiple instances of ONE service) behave more like a queue or like fan-out?
    More like a queue - within a single consumer group, each partition is consumed by only one instance at a time, so multiple instances split the work rather than each seeing every message. Broadcast-style fan-out only happens across different consumer groups, not within one.

A queue fan-out is like photocopying a memo and putting one copy in each department's physical inbox - you must remember to add a new inbox and copy for every new department. A log is like posting the memo on a shared company wiki page - anyone in any department can read it whenever they join, no extra copies needed.

saying these in an interview costs you the question

  • Says Kafka needs a separate topic per consumer, like a queue needs a separate queue
  • Doesn't know RabbitMQ needs a fanout/topic exchange plus multiple queues to broadcast
  • Thinks a new Kafka consumer group can read data older than the topic's retention window
  • Confuses consumer-group load-sharing with broadcast fan-out
  • Assumes adding a new queue consumer is free/config-less the same way a new Kafka consumer group is

context