Data Engineering glossary
What is a Consumer Group?
A consumer group is a set of Kafka consumers that share the work of reading a topic. Each partition is assigned to exactly one consumer in the group, so the group reads every record once while its members run in parallel. Separate groups read the same topic independently, each with its own committed offsets.
How it works
Consumers that use the same group.id form one group. A broker acting as group coordinator tracks the members and assigns partitions among them. The rules:
- Each partition goes to exactly one consumer in the group, which keeps per-partition ordering.
- One consumer can own several partitions.
- A group can use at most as many consumers as there are partitions; extra consumers sit idle as standbys.
- Each group commits its own offsets, so a billing group and an analytics group can read the same topic at different speeds.
When a member joins, leaves, crashes or stops polling for longer than max.poll.interval.ms, the group rebalances: partitions are reassigned. Older “eager” rebalancing stopped every consumer during the move. Cooperative rebalancing (CooperativeStickyAssignor) and, since Kafka 4.0, the new consumer group protocol (KIP-848) move only the partitions that need to change. Static membership (group.instance.id) avoids rebalances when a consumer restarts quickly.
Example
Kafka’s range assignment of a 6-partition topic: two consumers get three partitions each, three get two each, and a seventh consumer has nothing to do (Python 3.11).
def range_assign(partitions, consumers):
"""Kafka's RangeAssignor for one topic: contiguous blocks, the first consumers get one extra."""
consumers = sorted(consumers)
per, extra = divmod(partitions, len(consumers))
result, start = {}, 0
for i, c in enumerate(consumers):
n = per + (1 if i < extra else 0)
result[c] = list(range(start, start + n))
start += n
return result
for group in [["c1", "c2"], ["c1", "c2", "c3"], ["c1", "c2", "c3", "c4", "c5", "c6", "c7"]]:
print(f"{len(group)} consumers:", range_assign(6, group))
2 consumers: {'c1': [0, 1, 2], 'c2': [3, 4, 5]}
3 consumers: {'c1': [0, 1], 'c2': [2, 3], 'c3': [4, 5]}
7 consumers: {'c1': [0], 'c2': [1], 'c3': [2], 'c4': [3], 'c5': [4], 'c6': [5], 'c7': []}
Common mistakes
- Scaling consumers beyond the partition count and expecting more throughput.
- Doing slow work between polls, so consumers exceed
max.poll.interval.msand trigger rebalance storms. - Reusing one
group.idfor two different applications, which splits the partitions between them. - Committing offsets before processing during a rebalance, which can skip records.

