Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Consumer Groups

Consumer groups enable parallel processing of Kafka topics with automatic load balancing and fault tolerance. This guide covers group coordination, partition assignment strategies, and operational management.


Partition consumption by a single consumer and by a consumer groupPartition consumption by a single consumer and by a consumer groupSingle ConsumerConsumer GroupTopic (6 partitions)ConsumerNo parallelismTopic (6 partitions)Consumer 1Consumer 2Consumer 3Parallel processingAll partitionsP0, P1P2, P3P4, P5
GuaranteeDescription
Exclusive assignmentEach partition is assigned to exactly one consumer in a group
Independent groupsDifferent groups process messages independently
Automatic rebalancingPartitions are redistributed when consumers join or leave
Offset trackingEach group maintains its own offset position

Each consumer group has a coordinator broker responsible for:

  • Managing group membership
  • Coordinating rebalances
  • Tracking committed offsets
Join and sync exchange with the group coordinatorConsumer 1Group CoordinatorConsumer 2Consumer 1Consumer 1Group Coordinator(Broker)Group Coordinator(Broker)Consumer 2Consumer 2JoinGroupRequestJoinGroupRequestSelect leader(first consumer)JoinGroupResponse(leader, members)JoinGroupResponse(follower)SyncGroupRequest(assignments)SyncGroupRequest(empty)SyncGroupResponse(P0, P1, P2)SyncGroupResponse(P3, P4, P5)loop[Heartbeat]HeartbeatHeartbeat

The coordinator for a group is determined by:

coordinator_partition = hash(group.id) % __consumer_offsets_partitions
coordinator_broker = leader of coordinator_partition

Assigns consecutive partitions per topic to each consumer.

Range assignor partition distribution across two topicsRange assignor partition distribution across two topicsRange AssignmentTopic A: 6 partitionsTopic B: 6 partitionsConsumer 1Consumer 2Consumer 3P0P1P2P3P4P5P0P1P2P3P4P5

Characteristics:

  • Consecutive partition ranges per consumer
  • Same consumer gets same partition numbers across topics
  • Can cause imbalance with uneven partition counts
partition.assignment.strategy=org.apache.kafka.clients.consumer.RangeAssignor

Distributes partitions evenly across consumers.

ConsumerPartitions
Consumer 1A-P0, A-P3, B-P0, B-P3
Consumer 2A-P1, A-P4, B-P1, B-P4
Consumer 3A-P2, A-P5, B-P2, B-P5

Characteristics:

  • Even distribution across consumers
  • Partitions from different topics interleaved
  • All consumers should subscribe to the same set of topics
partition.assignment.strategy=org.apache.kafka.clients.consumer.RoundRobinAssignor

Minimizes partition movement during rebalances.

Sticky assignor partition retention when a consumer leavesSticky assignor partition retention when a consumer leavesBefore RebalanceAfter Rebalance (Sticky)C1: P0, P1C2: P2, P3C3: P4, P5C1: P0, P1, P4C2: P2, P3, P5C3 leaves groupOnly P4 and P5 movedC1 and C2 keep existing

Characteristics:

  • Retains as many assignments as possible
  • Reduces rebalance overhead
  • Enables stateful processing
partition.assignment.strategy=org.apache.kafka.clients.consumer.StickyAssignor

Combines sticky assignment with incremental cooperative rebalancing.

partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor

Benefits:

  • Partitions not needed by new assignment continue processing
  • Only revoked partitions pause processing
  • Minimal disruption during rebalances

Static membership (Kafka 2.3+) prevents rebalances when consumers restart with the same identity.

# Enable static membership
group.instance.id=consumer-instance-1
session.timeout.ms=300000
AspectDynamic MembershipStatic Membership
Restart handlingTriggers rebalanceNo rebalance if within timeout
IdentityAssigned by coordinatorConfigured group.instance.id
Timeout behaviorRemoved after session timeoutRetains assignment until timeout
Rolling restartsMultiple rebalancesZero rebalances

Static membership reduces rebalances; restarts within the session timeout avoid a rebalance when group.instance.id remains stable.

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka-consumers
spec:
replicas: 3
template:
spec:
containers:
- name: consumer
env:
- name: GROUP_INSTANCE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name # Uses pod name
String instanceId = System.getenv("GROUP_INSTANCE_ID");
props.put("group.instance.id", instanceId);

Terminal window
# List all consumer groups
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
# Describe a specific group
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group order-processors

Output:

GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST
order-processors orders 0 1000 1050 50 consumer-1-abc /192.168.1.10
order-processors orders 1 2000 2000 0 consumer-1-abc /192.168.1.10
order-processors orders 2 1500 1600 100 consumer-2-def /192.168.1.11
Terminal window
# Show group state and assignment
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group order-processors --state
StateDescription
EmptyNo active members
StableActive members, no rebalance
PreparingRebalanceRebalance starting
CompletingRebalanceWaiting for assignments
DeadGroup has no members and no offsets
Terminal window
# Reset to earliest
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group order-processors --reset-offsets --to-earliest \
--topic orders --execute
# Reset to specific offset
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group order-processors --reset-offsets --to-offset 1000 \
--topic orders:0 --execute
# Reset by timestamp
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group order-processors --reset-offsets \
--to-datetime 2024-01-01T00:00:00.000 \
--topic orders --execute
# Shift by offset
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group order-processors --reset-offsets --shift-by -100 \
--topic orders --execute
Terminal window
# Delete a consumer group (must be empty)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--delete --group order-processors

Multiple groups can consume the same topic independently:

Three consumer groups reading the same topic independentlyThree consumer groups reading the same topic independentlyGroup: order-processorsGroup: order-analyticsGroup: order-auditProcessConsumer 1ProcessConsumer 2AnalyticsConsumer 1AuditConsumer 1orders topicEach group maintainsindependent offsets
PatternDescription
Fan-outMultiple systems process same events
DevelopmentDev group doesn’t affect production
ReplayNew group processes historical data
A/B testingDifferent processing logic per group

The current consumer group protocol uses a centralized coordinator:

  1. Consumers send JoinGroup to coordinator
  2. Coordinator selects a consumer as leader
  3. Leader computes assignments
  4. Coordinator distributes assignments

Kafka 3.7+ introduces a new protocol with:

  • Server-side assignment computation
  • Reduced rebalance latency
  • No leader election needed
# Enable new protocol (Kafka 3.7+, preview)
group.protocol=consumer

Status: 3.7-3.8 early access; 4.0+ GA and recommended for new deployments.


FactorRecommendation
Consumer count<= partition count
Over-provisioningConsumers > partitions = idle consumers
ScalingAdd partitions before adding consumers
# Pattern: <service>-<function>-<environment>
order-service-processors-prod
payment-analytics-consumers-staging
inventory-sync-workers-dev
MetricAlert Threshold
Consumer lag> 10,000 messages
Rebalance frequency> 1 per hour
Empty groupUnexpected empty state
Consumer countDeviation from expected

Symptoms: High rebalance rate, consumer thrashing

Causes:

  • session.timeout.ms too low
  • Processing exceeds max.poll.interval.ms
  • Network instability

Solutions:

# Increase timeouts
session.timeout.ms=60000
max.poll.interval.ms=600000
heartbeat.interval.ms=15000

Symptoms: Some consumers idle, others overloaded

Causes:

  • More consumers than partitions
  • Imbalanced partition counts across topics

Solutions:

  • Ensure partitions >= consumers
  • Use RoundRobin or CooperativeSticky assignor

Symptoms: Group in PreparingRebalance state

Causes:

  • Consumer not responding
  • Network partition

Solutions:

Terminal window
# Stop the stuck consumer, then restart it after the group stabilizes.
# If the group is empty, you can delete it:
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--delete --group order-processors

In Kafka 4.2+ (KIP-1227), the Admin API exposes rack ID information in MemberDescription and ShareMemberDescription. This enables operators to verify rack-aware assignment correctness and diagnose unbalanced partition distribution across availability zones when using the DescribeConsumerGroups or DescribeShareGroups Admin APIs.