Consuming Messages

1. Creating Consumer Instance

Element Description Detail
KafkaConsumer Client that fetches records NOT thread-safe
One per thread Use separate instances No sharing
poll loop Drives fetch + heartbeat Call regularly

Example: Construct a consumer

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "billing");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

2. Setting Consumer Properties

Property Purpose Common Value
group.id Consumer group name App identifier
auto.offset.reset Start position when no offset earliest
enable.auto.commit Auto offset commit false for control

Example: Manual-commit config

props.put("enable.auto.commit", "false");
props.put("auto.offset.reset", "earliest");

3. Configuring Bootstrap Servers

Aspect Description Detail
bootstrap.servers Discovery brokers host:port list
Resilience List 2–3 brokers Failover
metadata.max.age.ms Refresh interval 300000

Example: Bootstrap servers

props.put("bootstrap.servers", "kafka1:9092,kafka2:9092");

4. Configuring Deserializers

Deserializer Type Class
String UTF-8 StringDeserializer
ByteArray Raw bytes ByteArrayDeserializer
Avro Schema KafkaAvroDeserializer

Example: Avro deserializer

props.put("value.deserializer", "io.confluent.kafka.serializers.KafkaAvroDeserializer");
props.put("schema.registry.url", "http://localhost:8081");
props.put("specific.avro.reader", "true");

5. Setting Consumer Group

Aspect Description Detail
group.id Shared identifier for cooperation Required to subscribe
group.instance.id Static membership ID Reduces rebalances
Scaling Add instances up to partitions Auto-balanced

Example: Static membership

props.put("group.id", "billing");
props.put("group.instance.id", "billing-pod-1");

6. Subscribing to Topics

Method Behavior Detail
subscribe(list) Dynamic, group-managed Triggers rebalance
subscribe(pattern) Regex topic match Auto-discovers
Rebalance Listener Hook on partition change Optional

Example: Subscribe to topics

consumer.subscribe(List.of("orders", "refunds"));
// Or pattern-based:
consumer.subscribe(Pattern.compile("metrics-.*"));

7. Polling Messages

Aspect Description Detail
poll(Duration) Fetch available records Blocks up to timeout
Heartbeat Sent during poll Keeps membership
Empty Result Returns empty if no data Loop continues

Example: Poll loop

while (running) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(200));
    for (ConsumerRecord<String, String> r : records) process(r);
}

8. Processing Records

Accessor Returns Detail
key() / value() Deserialized data Typed
partition() / offset() Position metadata For commits
timestamp() Record time ms epoch

Example: Access record fields

for (ConsumerRecord<String, String> r : records) {
    log.info("p={} o={} k={} v={}", r.partition(), r.offset(), r.key(), r.value());
}

9. Using Manual Assignment

Aspect Description Detail
assign() Bind specific partitions No group rebalance
No Auto-balance Caller manages assignment Full control
Use Case Exact partition consumption Replay, repair

Example: Manual assign

TopicPartition tp = new TopicPartition("orders", 0);
consumer.assign(List.of(tp));

10. Seeking to Position

Method Behavior Detail
seek(tp, offset) Jump to exact offset Next poll reads here
seekToBeginning() Earliest offset Full replay
seekToEnd() Latest offset Skip backlog

Example: Seek to offset

consumer.seek(new TopicPartition("orders", 0), 1500L);
consumer.seekToBeginning(consumer.assignment());

11. Closing Consumer

Aspect Description Detail
close() Commits, leaves group Triggers rebalance
timeout Max wait for clean shutdown Optional arg
wakeup() Interrupts blocked poll For shutdown

Example: Graceful shutdown

Runtime.getRuntime().addShutdownHook(new Thread(consumer::wakeup));
try { /* poll loop */ }
catch (WakeupException e) { /* expected */ }
finally { consumer.close(); }