Kafka Consumer Rebalancing: Eager Storms vs Cooperative Sticky Assignors
Group Coordinator broker, session.timeout.ms, and incremental rebalance protocols.
Part 12 in Series — Catch up on the previous article: Kafka Offset Management: Manual Commits, __consumer_offsets & Message Replay (Part 11) before diving into this post.
Suppose you operate a Kubernetes cluster running 20 consumer instances processing order events.
At 2:00 PM, a Kubernetes pod autoscaler detects high CPU utilization and scales up your deployment from 20 to 25 consumer pods.
Immediately, a event known as a Consumer Group Rebalance triggers.
Under older Kafka configurations, every single consumer instance in your cluster stops processing records, revokes all partition assignments, and sits idle for 45 seconds while re-negotiating assignments.
During those 45 seconds, consumer lag spikes, real-time dashboards freeze, and processing halts globally across all partitions.
Understanding consumer rebalancing mechanics is vital for eliminating “stop-the-world” processing pauses in production.
Why You Need This in Real Life
Rebalancing is Kafka’s protocol for redistributing partition assignments when consumer group membership changes.
- Rebalance Triggers: Adding a new consumer, shutting down a pod, or timing out on a long database call triggers a rebalance.
- Heartbeat vs Processing Timeouts: Distinguishing between
heartbeat.interval.ms(network liveness) andmax.poll.interval.ms(processing loop health) prevents spurious rebalance cascades. - Cooperative Rebalancing: Modern Kafka replaces “stop-the-world” partition revocations with incremental cooperative assignors that allow unaffected partitions to continue processing data mid-rebalance.
The Group Coordinator Broker
Kafka delegates group membership coordination to a specific broker called the Group Coordinator.
How the Group Coordinator is Selected:
- The consumer client hashes its
group.idstring:Math.abs("billing-service".hashCode()) % 50. - The result maps to a specific partition index in
__consumer_offsets. - The broker holding the leader replica for that
__consumer_offsetspartition becomes the Group Coordinator for that consumer group.
Consumer Group "billing-service"
|
v
Hash("billing-service") % 50 = Partition 14
|
v
Broker 3 (Holds Leader for __consumer_offsets-14) ===> GROUP COORDINATOR
All consumers in the group establish a background TCP connection to Broker 3 to send heartbeats and negotiate partition assignments.
What Triggers a Rebalance?
A rebalance is triggered whenever any of four conditions occur:
- Member Joins: A new consumer instance starts up and sends a
JoinGrouprequest. - Member Leaves: A consumer shuts down gracefully and sends a
LeaveGrouprequest. - Heartbeat Timeout Failure: A consumer crashes or loses network connectivity, failing to send a heartbeat within
session.timeout.ms(default: 45,000ms). - Processing Loop Timeout Failure: A consumer takes longer than
max.poll.interval.ms(default: 300,000ms / 5 minutes) to complete a single batch of records, signaling to the coordinator that the application thread is hung.
The Legacy Eager Rebalance Protocol: “Stop-the-World”
Prior to Kafka 2.4, consumer groups used the Eager Rebalance Protocol.
When a single new consumer joined the group:
EAGER REBALANCE PROTOCOL (Stop-the-World)
1. Coordinator signals Rebalance to ALL Consumers.
2. Consumer A REVOKES P0, P1 ---(Processing Halts Globally!)---> Sits Idle
3. Consumer B REVOKES P2, P3 ---(Processing Halts Globally!)---> Sits Idle
4. Group Leader calculates new assignments.
5. All Consumers receive new assignments and resume processing.
If one consumer pod crashed every 10 minutes in a large cluster, the group suffered continuous 30-second processing outages known as Rebalance Storms.
The Modern Solution: Cooperative Sticky Rebalancing
Introduced in Kafka 2.4 and made default in Kafka 3.0+, the Cooperative Sticky Assignor (CooperativeStickyAssignor) replaces eager revocations with incremental rebalancing.
Instead of revoking all partitions globally, consumers continue processing data on unaffected partitions throughout the rebalance!
COOPERATIVE STICKY REBALANCE (Incremental)
Initial State: Consumer A holds [P0, P1, P2]. New Consumer B joins group.
Phase 1:
- Consumer A keeps processing P0 and P1.
- Consumer A revokes ONLY Partition 2 (the specific partition moving to B).
- Consumer B joins and receives Partition 2.
Phase 2:
- Zero processing pauses on P0 and P1!
// Configure Cooperative Sticky Assignor in producer/consumer properties
props.put(
ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
org.apache.kafka.clients.consumer.CooperativeStickyAssignor.class.getName()
);
Tuning Rebalance Parameters to Avoid False Failures
Two configuration settings cause 90% of unintended production rebalances:
1. session.timeout.ms & heartbeat.interval.ms
A dedicated background thread inside KafkaProducer/KafkaConsumer sends heartbeat packets to the Group Coordinator broker.
heartbeat.interval.ms = 3000 # Send heartbeat every 3 seconds
session.timeout.ms = 45000 # Declare dead if no heartbeat for 45 seconds
If a temporary GC pause or network hiccup lasts longer than session.timeout.ms, the coordinator declares the consumer dead and triggers a rebalance.
2. max.poll.interval.ms & max.poll.records
If your code processes each record by calling a slow external REST API, processing a batch of 500 records (max.poll.records = 500) might take 6 minutes.
Because 6 minutes exceeds max.poll.interval.ms (5 minutes), the coordinator assumes the consumer thread is deadlocked and evicts it from the group.
How to Fix Processing Timeouts:
- Reduce
max.poll.recordsfrom 500 down to 50. - Increase
max.poll.interval.msto 600,000 (10 minutes).
Quick Summary
- The Group Coordinator is the broker node leading the
__consumer_offsetspartition assigned to yourgroup.id. - Heartbeat failures (
session.timeout.ms) and slow processing loops (max.poll.interval.ms) trigger rebalances. - Legacy Eager Rebalancing revokes all partitions, causing “stop-the-world” processing pauses.
CooperativeStickyAssignorperforms incremental rebalancing, allowing unaffected partitions to stream data without interruption.
References & Further Reading
- Apache Kafka Wiki. KIP-500: Replace ZooKeeper with a Self-Managed Metadata Quorum. Kafka Improvement Proposals.
- Apache Kafka Wiki. KIP-595: A Raft-based Metadata Quorum Specification (KRaft). Kafka Improvement Proposals.
- Ongaro, D., & Ousterhout, J. (2014). In Search of an Understandable Consensus Algorithm (Raft). USENIX ATC ‘14.
Part 13: Kafka Partition Replication: High Watermark, LEO & In-Sync Replicas (ISR)
Continue to Part 13 →