具有相同组ID的Kafka使用者线程消耗相同的记录

时间:2018-10-14 16:28:36

标签: java multithreading apache-kafka kafka-consumer-api producer-consumer

我需要在多个线程中使用Kafka分区中的记录,并在每个线程上使用唯一记录进行处理。  我有以下代码,我不知道出了什么问题

public class ConsumerThread implements Runnable {
    public String name;
    public ConsumerThread(String name){
        this.name = name;
    }
    public Properties getDefaultProperty(){
        Properties prop = new Properties();
        prop.setProperty("group.id", "4");
        prop.put("enable.auto.commit", "false");
        prop.put("auto.offset.reset", "earliest");
        prop.setProperty("bootstrap.servers", "localhost:9092");
        prop.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.setProperty("max.poll.records","150");
        return prop;
    }
    public void run() {
        TopicPartition tp = new TopicPartition("my.topic", 0);
        KafkaConsumer consumer = new KafkaConsumer(getDefaultProperty());
        ArrayList tpList = new ArrayList<TopicPartition>();
        tpList.add(tp);
        consumer.assign(tpList);
        ConsumerRecords poll = consumer.poll(1000);
        Iterator it = poll.iterator();
        consumer.commitAsync();
        while(it.hasNext()){
            ConsumerRecord cr = (ConsumerRecord) it.next();
            System.out.println("From "+this.name+" : "+cr.value());
        }
        consumer.close();
        System.out.println("Thread Exiting "+this.name);
    }
}

结果

From Thread1 : produced_0
From Thread1 : produced_1
From Thread1 : produced_2
From Thread1 : produced_3
.
.
.
From Thread1 : produced_136
From Thread2 : produced_0
From Thread2 : produced_1
From Thread2 : produced_2
From Thread2 : produced_3
.
.
.


预期:

From Thread1 : produced_0
From Thread1 : produced_1
From Thread1 : produced_2
From Thread1 : produced_3
.
.
.
From Thread1 : produced_136
From Thread2 : produced_4
From Thread2 : produced_5
From Thread2 : produced_6
From Thread2 : produced_137

2 个答案:

答案 0 :(得分:0)

只有使用kafka使用者的subscribe方法才能将分区自动分配给使用者组。 但是,您将assign与特定的主题分区一起使用,因此您承担了将特定的分区分配给不同使用者的责任(但是您始终使用相同的分区0,因此所有使用者都使用同一主题分区)

答案 1 :(得分:0)

就像Lior Chaga在他的评论中所说,您正在手动为您的消费者分配主题分区。这不是推荐的方法。最重要的是,似乎所有使用者都使用相同的完全相同的groupID。在这种配置下,如果消耗两个线程,则至少有一个使用方收到一条特定的消息,则其他线程中的 none 都不会得到该消息。如果您希望所有使用者线程都彼此拥有自己的“消息”集,而又不会互相干扰,则需要给它们提供不同的group.id

要订阅某个主题,以便该主题可以为您处理自动平衡然后消费,您应该执行以下操作(摘自下面链接的KafkaConsumer javadoc):

 consumer.subscribe(Arrays.asList("foo", "bar"));
 while (true) {
     ConsumerRecords<String, String> records = consumer.poll(100);
     for (ConsumerRecord<String, String> record : records)
         System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
 }

官方的Kafka javadocs有更多详细的解释: https://kafka.apache.org/20/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html