Under The Hood
backend springboot Spring Kafka 3.x / Kafka 3.x

Spring Kafka: @KafkaListener, Consumer Rebalancing, Offset Commits

Last updated
Prerequisites:
Kafka topics, partitions, consumer groups
Spring Boot basics
  • spring
  • kafka
  • kafka-listener
  • consumer-group
  • rebalance
  • offset

Read at your depth

The practical view

Spring Kafka consumes messages with @KafkaListener(topics = "orders", groupId = "order-service"). Configure with KafkaListenerContainerFactory (concurrency = consumers per listener). Offsets are committed automatically by default (auto.offset.reset, enable.auto.commit) — for at-least-once semantics. For exactly-once-ish processing, use manual ack: AckMode.MANUAL and acknowledge(). Handle rebalances with ConsumerRebalanceListener (onPartitionsRevoked/Assigned) if you need state cleanup or final offset commit. Errors: @RetryableTopic for retries with dead-letter topics, ErrorHandler / SeekToCurrentErrorHandler for failure handling.

The same idea in other frameworks

react equivalent
N/A — server-side Spring/Kafka concern.

Legacy vs modern

Auto-commit at-least-once vs manual ack with error handling

Default auto-commit gives at-least-once but can lose the offset on crashes and cannot react to failures; manual ack with retry gives control.

before → after
Default auto-commit listener
@KafkaListener(topics = "orders", groupId = "svc")
public void on(Order o) { // ❌ OLD: auto-commit, no failure handling
  process(o);
}
Manual ack + retryable topic
@RetryableTopic // ✅ NEW: retries + dead-letter
@KafkaListener(topics = "orders", groupId = "svc")
public void on(Order o, Acknowledgment ack) {
  process(o);
  ack.acknowledge(); // ✅ NEW: commit only after success
}

Interview gotchas

Context

This is the critical Kafka reliability question — interviewers want the rebalance window and its effect on at-least-once vs at-most-once, which determines whether messages duplicate or are lost.

The mechanical answer

During a rebalance, partitions are reassigned from one consumer to another. A consumer that processed records but had not yet committed their offsets loses those uncommitted positions: when the new owner of the partition starts, it resumes from the last committed offset, so the records between the last commit and the rebalance are PROCESSED AGAIN — this is the at-least-once duplication window. If instead you committed offsets BEFORE processing (at-most-once), a rebalance skips records that were committed but not processed — message loss. There is no way to get exactly-once without extra machinery (idempotent processing or the transactional exactly-once API). This is why the ack/commit timing is the central design decision: with at-least-once, you must make processing idempotent to tolerate replays.

Trap

The naive answer is 'rebalance just redistributes partitions'. It also reopens the delivery window — uncommitted records replay. Another trap: assuming auto-commit means 'commit after each message' — it commits on a timer (auto.commit.interval.ms), so a crash can replay far more than one record. Candidates who tie offset timing to the delivery guarantees show real Kafka understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.