Kafka
Kafkalistener
Offset Setting
Programming
Coding Tutorial

How to set offset in kafkalistener

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Apache Kafka is a robust, distributed event streaming platform capable of handling trillions of events a day. It is designed to handle vast amounts of data and facilitates real-time data pipelines and streaming apps. Additionally, Kafka provides message storage capabilities that allow consumers to fetch messages at a specific point defined by an offset. Understanding how to correctly set and manipulate the offset in @KafkaListener is crucial for developing flexible and reliable Kafka-based applications.

Understanding Kafka Offsets

An offset is a unique identifier for each record in a partition of a topic in Kafka, signifying the position of the record. Kafka maintains the sequence of records in a partition, and the consumer tracks which records have been consumed by storing the offset. Each record in a particular partition has a unique, sequential identifier called its offset. The consumer saves the next offset to read after it processes a batch of messages. Thus, offset handling is fundamental for achieving correct message processing, especially in failure recovery or selective processing scenarios.

Setting Offset in @KafkaListener

In Spring Kafka, @KafkaListener is an annotation used to create message listener containers that consume messages from specified Kafka topics. To control message consumption, such as specifying where to start or resume, you can manipulate the offset in @KafkaListener. However, configuring the offset directly through @KafkaListener is not supported. Instead, you will need to use additional configuration in ConsumerConfig or utilize ConsumerSeekCallback for finer control.

1. Using ConsumerConfig

Setting the initial offset can be achieved by configuring the ConsumerConfig. Below are the properties related to offsets:

  • auto.offset.reset: This property determines the behavior when no initial offset is found for a consumer’s group ID or if the current offset does not exist anymore on the server (e.g., if that data was deleted):
    • earliest: automatically resets the offset to the smallest offset.
    • latest: automatically resets the offset to the largest offset.
    • none: will throw an exception to the consumer if no previous offset is found for the consumer's group.
java
1@Configuration
2public class KafkaConfig {
3    @Bean
4    public ConsumerFactory<String, String> consumerFactory() {
5        Map<String, Object> props = new HashMap<>();
6        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
7        props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group");
8        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
9        return new DefaultKafkaConsumerFactory<>(props);
10    }
11    
12    @Bean
13    public ConcurrentKafkaListenerContainerFactory<String, String> 
14      kafkaListenerContainerFactory() {
15        ConcurrentKafkaListenerContainerFactory<String, String> factory =
16          new ConcurrentKafkaListenerContainerFactory<>();
17        factory.setConsumerFactory(consumerFactory());
18        return factory;
19    }
20}

2. Dynamically Setting Offsets Using ConsumerSeekCallback

If you need to set or modify offsets dynamically during runtime, implement ConsumerSeekAware. This interface provides access to ConsumerSeekCallback, which can be used for seeking to specific offsets on initialization or during consumption.

java
1@Component
2public class DynamicOffsetListener implements ConsumerSeekAware {
3    @KafkaListener(topics = "topicName", groupId = "test-group")
4    public void listen(ConsumerRecord<?, ?> record) {
5        // processing logic here
6    }
7
8    @Override
9    public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
10        assignments.forEach((tp, pos) -> callback.seek(tp.topic(), tp.partition(), calculateOffset(tp)));
11    }
12
13    private long calculateOffset(TopicPartition tp) {
14        // Determine offset based on custom logic
15        return 0L; // example static offset
16    }
17}

Guidelines for Managing Offsets

ConsiderationDescription
ConsistencyEnsure processed offsets are consistent with the state of your application. Batch and transaction management techniques should be employed to commit offsets and application state atomically.
Failure handlingOn application or consumer failure, the offset should be such that no records are skipped or duplicated when the consumer restarts.
Offset storageBy default, Kafka stores offsets in a Kafka topic called __consumer_offsets. Alternatively, customized storage can be implemented using external systems.
PerformanceFrequent commits of offsets can impact performance, while less frequent commits can risk reprocessing messages in the event of a failure. Find a balance based on your use case.

Conclusion

Proper handling of Kafka offsets is vital for ensuring robust message consumption and maintaining accuracy and efficiency in distributed data streaming applications. Kafka provides flexible configurations and API hooks to set and manage offsets according to varying requirements. Using these appropriately will allow fine-grained control over message processing, greatly enhancing the capability of your real-time data handling applications.

This understanding and application of Kafka offsets, especially through @KafkaListener, play a crucial role in building scalable and fault-tolerant systems that leverage Kafka's powerful event-streaming paradigm.


Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design