Lesson 3 · Foundations
Consumer groups & rebalancing
How Kafka scales reading out — and heals when a consumer dies.
Your win: explain how a group splits a topic's partitions, what happens when a consumer joins or crashes, and why two groups on the same topic each get their own copy of the events.
A group is how consumers cooperate
A consumer group is a set of consumers sharing one group id. The rule that defines everything else: each partition is read by exactly one member of the group.1 Kafka hands out the partitions among the members — that's how the group divides the work.
So the number of partitions is the ceiling on useful consumers in a group.
In our wrapper, Instances(n) is how a service says "run n
members in this group" — notification's async consumer runs
Instances(2) to read two partitions at once.2
Your group ids, decoded
Our wrapper builds a group id for every (service, topic) pair:
internal/golibs/kafka/kafka.go:255GenNewConsumerGroupID(service, topic)
→ "{prefix}{service}.consumer-group.{topic}"
→ "prod.tokyo.spike.consumer-group.communication.email-sending"
That naming is doing real work. Because each service gets its own group id on a topic, groups are independent: they each track their own committed offset, so they each receive every event.
arch.student-course-class-with-academic-year — but with
different group ids (one per service). So both services see every
class-membership event and sync independently. Same topic, two groups, two
copies. That's pub/sub fan-out.
Rebalancing: what happens when membership changes
When a consumer joins, leaves, or dies, the group rebalances — Kafka reassigns the partitions across the surviving members.1 Consumption pauses briefly during the reshuffle, then resumes. A crashed member's partitions are picked up by the others, from the last committed offset — so nothing is silently skipped (though something may be re-processed; that's Lesson 5).
This is also why our services care so much about liveness: if a consumer goroutine
dies, the /healthz endpoint returns 503 and Kubernetes restarts the pod
(cmd/server/notificationmgmt/consumers.go:110),
triggering a clean rebalance rather than leaving partitions unread.
The two-lane pattern, now it makes sense
spike runs the same handler on two topics —
communication.email-sending and its .high-priority sibling —
each with its own group. Because the groups are independent, a huge backlog on the
normal lane can't delay the high-priority lane: different partitions, different group,
same pod (internal/spike/.../kafka/send_email_consumer.go:39).
We'll give this pattern a full lesson later.
Confluent — Consumers, Consumer Groups & Offsets
The authoritative walkthrough of group membership, the one-partition-per-member rule, and rebalancing. Pair it with the Kafka 101 "Consumers" video.
→ docs.confluent.io/kafka/design/consumer-design.html
→ Kafka 101 — Consumers
Check yourself (from memory)
Q1. Within one consumer group, each partition is read by…
Q2. Two services consume one topic with different group ids. Each service…
Q3. A consumer in a group crashes. Kafka responds by…
Instances(n) sets how many
members the group runs.1. Confluent — Kafka Consumer Design (groups, one-partition-per-member, rebalancing).
2. Repo: repo-kafka-map.md — consumer options & wiring (Instances(n), GenNewConsumerGroupID).