Module 26 / 46 · Phase F — Event-Driven at Scale · opener · 50 min

Message
brokers
deep dive.

Services calling services synchronously is fine until the third one is down. Brokers are how modern systems hand off work across failures, across time, and across teams. The infrastructure layer powering Uber, LinkedIn, Stripe, and most of the modern internet's spine.

// What you'll know by the end

  • Why brokers exist (and what they decouple)
  • Queue vs log: the two broker paradigms
  • Kafka's anatomy: partitions, consumer groups, offsets
  • Delivery semantics — at-most, at-least, exactly-once
§ 01 — The pain that brokers solve

Service A calls B
calls C. What could
go wrong?

A user clicks "place order." Your order service writes to the database, calls the payment service, calls the inventory service, calls the email service, calls the analytics service, calls the recommendation service. Six synchronous network calls happen before the user sees a confirmation page. Each call has its own latency, its own failure rate, its own deploy cadence, its own team. Any one of them being slow or down makes the entire chain slow or down. This is the architecture that worked for the first ten engineers and breaks for the next hundred.

// FAILURES OF THE FULLY-SYNCHRONOUS WORLD
i
Latency stacks. Each downstream call adds its p99 to yours. Six calls at 50ms each = ~300ms floor, plus tail. Your user waits.
With a broker: publish the order event, return success immediately. Everything downstream happens in parallel, off the request path. User-perceived latency drops to one local write.
ii
Failures cascade. Email service is down? The order fails. Inventory service is slow? Orders queue up at the gateway. One service's bad day = everyone's bad day.
With a broker: the producer doesn't know or care if consumers are down. They'll catch up when they come back. Failure of one service no longer fails the whole flow.
iii
Coupling is forever. Adding a new downstream consumer means modifying the producer to call it. Removing one breaks the producer. Six consumers = six lines of fragile code in your hot path.
With a broker: consumers subscribe themselves. The producer publishes once, fan-out is free. New use cases ship without touching upstream code.
iv
No replay. A bug in the analytics service drops events for an hour. Those events are gone — the order service has long since moved on. Data lost forever.
With a broker (log-based): messages are retained. Fix the bug, rewind the consumer's offset, replay the hour. Recovery is a config change, not a war room.

The shorthand for what a broker provides is decoupling along three axes: spatial (producer and consumer don't need each other's address), temporal (they don't need to be up at the same time), and logical (one producer's event can drive many independent consumers). Add to that durability (the broker is the system of record for in-flight events), and you have the four properties that made event-driven architecture eat the world from 2011 onward.

A broker is what lets one team's "I shipped this event" become twelve other teams' "I built something on it."

The rest of this module covers the broker landscape (§02 — queues vs logs, the two paradigms), Kafka's anatomy in detail (§03), a live simulator that walks through partitioning and consumer-group rebalancing (§04), and the delivery semantics that decide what kinds of correctness you actually get (§05).

§ 02 — Two paradigms: queue vs log

Delivered & gone,
or kept forever?

Every message broker is some variation on one of two designs: a queue (where consuming a message removes it) or a log (where consuming reads from a position; the message stays). Both exist for good reasons; they fit different workloads. Picking the wrong one is one of the most common architecture mistakes in mid-stage startups.

// THE TWO BROKER PARADIGMS · SIDE BY SIDE

// QUEUE-BASED
Queue
(work distribution)
"One message in. One worker takes it. Done — it's gone."
PROD queue · FIFO WORKER WORKER

Messages live in a queue. Workers pull one at a time, process it, and ack. On ack, the message is deleted. If a worker dies mid-processing, the message returns to the queue for another worker. Multiple workers compete for messages — load is balanced naturally. Built for task distribution: each job done exactly once by one worker.

// canonical queue brokers
RabbitMQAWS SQSActiveMQBeanstalkdSidekiq (Redis)
// LOG-BASED
Log
(event stream)
"One message in. Every subscriber reads it. Still there."
PROD log · append-only CONS A · ofs=5 CONS B · ofs=3 CONS C · ofs=0

Messages are appended to an immutable log. Each consumer maintains its own offset — a position in the log it's reading from. Reads don't remove anything. Many consumers can read the same stream at their own pace, going backward to replay or forward to catch up. Built for event streams: a published event drives many independent reactions.

// canonical log brokers
Apache KafkaApache PulsarAWS KinesisRedpandaRedis Streams

The mental shorthand: queues are for tasks; logs are for events. Tasks have one rightful executor (process this payment, send this email, encode this video) — you want exactly one worker to claim it. Events are facts that may have many independent consequences (user signed up — kick off welcome email, create profile, log to analytics, train recommender). Pick a queue when there's work to be done; pick a log when there are facts to be broadcast.

The reason logs took over the modern event-driven world (Kafka shipping at LinkedIn in 2011, then becoming the lingua franca everywhere) is that logs subsume queues. You can implement queue semantics on top of a log (single consumer group, ack via offset commit) — but you can't implement log replay on top of a queue. The log is the more powerful primitive. For new systems with diverse downstream consumers, defaulting to a log is almost always the right call. NATS, Kinesis, and Redis Streams all followed Kafka's lead. RabbitMQ added log-like streams in 2021. The industry voted.

§ 03 — Kafka anatomy

Topics, partitions,
offsets, groups.

Since logs won, and Kafka is the canonical log broker, every engineer working on event-driven systems needs to understand its anatomy. Five concepts. The whole architecture pivots on them. The same vocabulary applies to Pulsar, Kinesis, Redpanda, NATS streams — Kafka set the schema.

// KAFKA'S CORE OBJECTS · ONE DIAGRAM, FIVE CONCEPTS

KAFKA TOPIC · user-events PRODUCER writes events with keys topic = "user-events" · 4 partitions P0 → 0 1 2 3 4 P1 → 0 1 2 P2 → 0 1 2 3 P3 → 0 1 → offset consumer-group: ANALYTICS C1 → P0, P1 C2 → P2, P3 consumer-group: BILLING C3 → P0, P1, P2, P3 (separate offsets!) consumer-group: SEARCH C4 → P0, P1 · C5 → P2, P3 (its own offset state)
Topic

A named stream of events of a single logical type. Producers publish to a topic; consumers subscribe to a topic. A typical Kafka cluster has hundreds or thousands of topics: user-events, order-placed, page-views, payment-completed, etc.

Partition

A topic is split into N partitions — each is an independent ordered log. Messages with the same key always land in the same partition (hash(key) % N). Partitions are the unit of parallelism: each partition can be consumed by a different worker concurrently.

Offset

A monotonically increasing integer identifying each message's position within its partition. Consumers track their progress as offsets — "I've processed up to offset 1,247." Offsets are how Kafka does replay: reset your offset to 0 and re-read everything.

Consumer Group

A set of consumers cooperating to consume a topic. Each partition is assigned to exactly one consumer in the group. Add a consumer → partitions get rebalanced. Each group has its own offset state, so multiple groups can consume the same topic independently — analytics, billing, and search can all read the same stream at their own pace.

Broker (the cluster)

A Kafka cluster is multiple broker servers, with partitions replicated across them. One broker is leader for each partition; others are followers. Replication factor 3 is standard — survives 2 broker failures. Producers and consumers connect to the leader; followers exist for durability.

The two most important consequences to internalize: (1) ordering is only guaranteed within a partition, not across them. If you need strict global order, you need one partition (and you give up parallelism). If you need order per user, use the user ID as the message key — all that user's events land in the same partition and get processed in order. (2) Consumer groups give you both load distribution and broadcast for free. Multiple consumers in one group share the work; multiple groups each read the entire stream. This is the schema that lets Kafka power a dozen downstream systems off one event stream.

Partitions are the unit of parallelism. Consumer groups are the unit of independent consumption. Everything else is detail.
§ 04 — Kafka topic simulator · interactive lab

Producer publishes.
Consumers balance.

Below: a Kafka topic with 4 partitions, a consumer group, and a stepping scenario that demonstrates partitioning by key, consumer assignment, and the rebalance dance that happens when consumers join or leave the group. Eight frames; by the end, the mental model is concrete.

KAFKA.SIM // m.26 lab
Step 0 / 0
// TOPIC "user-events" · 4 partitions
SCENARIO READY
Press Next to begin
"Walk through the lifecycle: produce, consume, rebalance."
Topic user-events with 4 partitions, one consumer group "analytics" starting with a single consumer. Watch what happens as the group grows and shrinks.
// consumer group: analytics
C1P0P1P2P3
§ 05 — Delivery semantics

How certain
is "delivered"?

Every broker promises to deliver messages. The fine print is how reliably — and the three options have very different cost and correctness implications. The choice has to match the work the consumer is doing: logging vs counting vs charging credit cards demand different guarantees. Pick the wrong one and either lose data or duplicate operations. Both are bad in different ways.

// THE THREE DELIVERY SEMANTICS · COST VS CORRECTNESS

// AT-MOST-ONCE
Fire and forget
"Message might arrive zero or one times. Never twice."

Producer sends without waiting for ack; consumer commits offset before processing. If anything fails, the message is gone. Cheapest, lowest latency. Lossy by design.

USE FOR:
metrics, telemetry, page-view tracking — anywhere data loss is acceptable in exchange for speed.
// AT-LEAST-ONCE
Try until acked
"Message will arrive one or more times. Never zero."

Producer retries until broker acks; consumer commits offset only after processing. On crash mid-processing, the message is re-delivered. Duplicates are possible — the consumer must be idempotent.

USE FOR:
most workloads, with idempotent handlers. Default in Kafka, RabbitMQ, SQS. The pragmatic choice.
// EXACTLY-ONCE
Once and only once
"Message arrives exactly one time. No loss, no duplicates."

Requires transactional commits across broker, consumer, and any downstream effects. The hardest guarantee. Kafka's exactly-once semantics (since 0.11) work for Kafka-to-Kafka pipelines but get tricky when external systems are involved.

USE FOR:
financial events, billing, audit logs. Pay the cost only where the cost is justified. Deep dive in M.31.

The honest answer most teams converge on: at-least-once delivery + idempotent consumers. The infrastructure side is simpler (no distributed transaction across systems), and the application side just has to deduplicate — usually by attaching a unique event ID and checking "have I processed this before?" in the consumer. This pattern is so common it has a name: the "outbox pattern", where producers write events to an outbox table within their database transaction, then a separate process publishes from the outbox to the broker. Effectively gives you exactly-once at the boundary, with at-least-once underneath.

One critical pitfall: don't confuse "exactly-once delivery" with "exactly-once processing". Kafka can guarantee the message reaches the consumer once — but if your consumer crashes after processing but before acking, the message gets redelivered. To get true exactly-once effects, you need idempotency in the handler. Marketing copy often blurs this distinction. The papers and the production reality don't. M.31 will dig in.

Default to at-least-once + idempotent. Reach for exactly-once only when something irreversible is on the line.
§ 06 — Eight words for the broker conversation

Vocabulary,
for the stream.

The terms every Kafka tutorial, every event-driven architecture review, and every distributed log paper assume you already know.

Topic
/ˈtɒp.ɪk/
A named stream of events of a single logical type. Producers publish; consumers subscribe. The basic unit of organization in Kafka, Pulsar, Kinesis, NATS streams.
Partition
/pɑːrˈtɪʃ.ən/
An ordered, immutable log within a topic. Messages with the same key always land in the same partition via hash(key) % N. The unit of parallelism — one consumer per partition per group.
Offset
/ˈɒf.set/
A monotonically increasing integer identifying a message's position in a partition. Consumers track their progress as offsets and commit them back to the broker. Replay = reset offset.
Consumer Group
/kənˈsuː.mə ɡruːp/
A set of consumers cooperating to read a topic. Each partition assigned to exactly one consumer in the group. Multiple groups read the same topic independently, each with its own offset state.
Rebalance
/ˌriːˈbæl.əns/
The process of reassigning partitions to consumers when a group's membership changes (consumer joins, leaves, or dies). Briefly pauses consumption while assignments shuffle. Optimize this for tight SLAs.
ISR · In-Sync Replicas
/aɪ ɛs ɑːr/
The set of partition replicas currently caught up with the leader. Writes are considered durable when acked by all ISRs (with acks=all). The Kafka equivalent of the Raft quorum from M.24.
Log Compaction
/kəmˈpæk.ʃən/
Kafka's option to retain only the latest value per key, instead of full history. Used for changelog topics — gives you a queryable "current state" stream while still being a log.
Idempotency
/ˌaɪ.dɛm.poʊˈten.si/
A property where executing an operation multiple times has the same effect as executing it once. The application-side requirement for safe at-least-once consumption. Usually achieved with event IDs and a "have I seen this before?" check.
§ 07 — Knowledge check

Five questions.
Subscribe to the stream.

Test the broker intuition. Click an answer; explanation drops in instantly.

QUESTION 1 OF 5
Loading question...
Score: 0 / 5
5 / 5

Subscribed.

Perfect. Brokers, Kafka anatomy, delivery semantics — all internalized. Next: pub/sub patterns and topologies.

§ 08 — The recap

Three ideas to
carry forward.

The infrastructure layer that makes everything from here onward possible. These ideas return in every event-driven module.

i

Decouple via the broker

Producers don't know consumers. Consumers don't know producers. The broker is the contract. Spatial, temporal, and logical decoupling — the three axes that make systems composable.

ii

Log beats queue for events

Logs subsume queues. Logs let you replay, fan out to many independent consumers, and add new use cases without touching producers. The default for new systems.

iii

At-least-once + idempotent

The pragmatic default. Exactly-once is technically possible but expensive and brittle across boundaries. Build idempotency into your consumers; sleep at night.

↓ UP NEXT

M.27 — Pub/Sub patterns
& topologies.

You have a broker. Now: how do you actually wire it up? Topic-per-event-type vs catch-all topics. Fanout, work queue, request-reply. Dead-letter queues. The patterns that turn "we have Kafka" into "we have a working event-driven architecture."

Continue to Module 27 →