Kafka
Consumer Messaging
Spring Framework
Distributed Systems
Topic Consumption

Spring Kafka multiple consumer for single topic consume different messages

System Design practice on Codemia

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

Practice system design

In the world of real-time data processing, Apache Kafka has emerged as a popular distributed event streaming platform, capable of handling high-throughput data pipelines. Kafka's powerful messaging system allows for fault-tolerant storage and distribution of massive streams of records. In applications where multiple consumers need to process messages from a single Kafka topic, configuring consumers efficiently becomes crucial for optimizing performance and resource utilization. The setup where Spring Kafka is employed to manage multiple consumer instances for a single topic, with a focus on consuming different messages, is of particular interest.

Understanding Kafka Consumer Groups and Partitions

To start with, Kafka topics are split into partitions to allow the data to be distributed and parallelized — this means multiple consumers can read from a topic in parallel without interfering with each other. Each partition of a topic can be read by only one consumer in a consumer group at a time. This model provides both scalability and fault tolerance. Consumers within the same group coordinate with each other to cover all partitions and hence, the entire topic.

Spring Kafka Configuration

Spring Kafka abstracts some of Kafka's complexities and provides a simpler, annotation-based model to work with. For a scenario where you have multiple consumers on a single topic that should process different messages, the appropriate setup within Spring Kafka typically involves certain considerations:

  1. Consumer Configuration: Each consumer instance needs to be correctly configured to connect to the Kafka cluster and join the appropriate consumer group. This is typically done in the application.properties or application.yml file in Spring applications.
  2. Concurrent Message Consumption: To enable multiple consumers within the same application or service to consume different messages, one would typically configure ConcurrentKafkaListenerContainerFactory. This factory allows setting the concurrency level, which essentially defines the number of consumer threads.
java
1    @Bean
2    public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
3        ConcurrentKafkaListenerContainerFactory<String, String> factory =
4            new ConcurrentKafkaListenerContainerFactory<>();
5        factory.setConsumerFactory(consumerFactory());
6        factory.setConcurrency(3);  // Number of concurrent threads
7        return factory;
8    }
  1. Partition Assignment: In cases where manual partition assignment is necessary (say, when specific consumers need to always read specific partitions), partitions can be assigned directly to different consumer instances. This is managed by setting partition assignment in the listener:
java
1    @KafkaListener(topicPartitions = @TopicPartition(topic = "topicName", partitions = { "0" }))
2    public void listenPartition0(String message) {
3        // processing logic for partition 0
4    }

Load Balancing and Fault Tolerance

When using multiple consumers, it’s vital to consider load balancing and fault tolerance. Kafka provides built-in capabilities for redistributing partitions among available consumer instances in case a consumer fails. This capability is automatic and helps to ensure that data processing can continue even in the case of individual consumer failures.

Example: Practical Implementation in Spring Kafka

Here is how different parts of a Spring application would come together to set up a multi-consumer configuration:

  • application.yml Configuration:
yaml
1    spring:
2      kafka:
3        consumer:
4          bootstrap-servers: localhost:9092
5          group-id: my-group
6          auto-offset-reset: earliest
7          key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
8          value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
  • Consumer Logic:
java
1    @Service
2    public class KafkaConsumers {
3        @KafkaListener(topics = "topicName", groupId = "group1")
4        public void consumeMessageGroup1(String message) {
5            System.out.println("Received Message in group1: " + message);
6        }
7
8        @KafkaListener(topics = "topicName", groupId = "group2")
9        public void consumeMessageGroup2(String message) {
10            System.out.println("Received Message in group2: " + message);
11        }
12    }

Key Points Summary

AspectDetails
Consumer GroupsMultiple consumers can join a group to share workload of consuming messages.
Partition ManagementConsumers within a group auto-manage partitions unless explicitly configured.
Fault ToleranceKafka and Spring handle consumer failures by rebalancing partitions among active consumers.
Load BalancingSetting concurrency in ConcurrentKafkaListenerContainerFactory balances load among consumers.
Practical ConfigurationUse application.yml for common properties and @KafkaListener for method-specific configs.

In summary, configuring multiple consumers for a single topic in Kafka using Spring Kafka involves a combination of setting up consumer properties, understanding consumer group behaviors, and optionally, managing partition assignments. By leveraging these features, applications can achieve scalable, robust, and efficient message consumption.


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