Kafka Consumer仅在产生“足够”的数据后读取

时间:2019-05-17 01:21:29

标签: java spring-boot apache-kafka kafka-consumer-api

我正在spring-boot中实现一个端点,该端点在被调用时将转储位于kafka主题中的所有消息(用于测试)。

我期望的行为是,当生产者写到“ testTopic”主题,随后消费者进行民意测验时,它应该阅读刚刚产生的消息。

我观察到的行为是使用者无法使用产生的消息。此外,如果生产者产生更多的消息(例如10-15),则消费者将一次性丢弃所有消息。从这一点开始,如果生产者甚至生成一条消息,那么消费者将按预期进行消费。

直觉上,我认为设置FETCH_MIN_BYTES_CONFIG可能与此有关-也许使用者正在等待写入足够的字节。但这已设置为1字节(默认值),并且不能解释随后成功读取单个消息的过程。

接下来,我想也许我是在创建主题之前就在注册使用者(通过太快地调用注册端点)。但是我从kafka-topics.sh确认,在注册使用者之前,该主题存在。

我注意到,如果启用了偏移自动提交功能,则该行为有时是预期的,有时不是预期的。手动提交偏移量(在下面的代码中未显示)时,行为非常奇怪,如上所述。

我还知道制作人正在通过使用kafka-console-consumer进行确认来按预期工作。

还尝试将轮询超时增加到1秒,但是没有运气。

// Consumer
@Component
public class TestConsumer{
    private KafkaConsumer testConsumer = null;

    public void registerConsumer(final String consumerId) {
        if (consumer == null) {
            Properties props = new Properties();
            props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "<some_address>:<some_port>");
            props.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
            props.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
            props.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "testGroup");

            testConsumer = new KafkaConsumer<String, String>(props);
            testConsumer.subscribe(Collections.singletonList("testTopic"));
        }
        else{
            logger.debug("Consumer already registered");
        }
    }

    public Map<String, List<String>> consume() {
        Map<String, List<String>> messages = new HashMap<>();
        if (testConsumer == null){
            logger.error("testConsumer was not instantiated");
            return null;
        }
        ConsumerRecords<String, String> records = testConsumer.poll(Duration.ofMillis(100));
        List<String> buffer = new ArrayList<>(); 
        for (ConsumerRecord<String, String> record: records){
            logger.debug(String.format("Consuming %s", record.value()));
            buffer.add(record.value());
        }
        messages.put("data", buffer);
        return messages;
    }
}

步骤顺序为: 1. Spring Boot应用程序启动 2. kafka主题已创建,我可以通过kafka控制台进行确认 3.我注册生产者和消费者 4.生产者进行生产,我可以使用kafka控制台(不同的消费者组)进行确认 5.消费者无法消费

我希望结果如下:

{
    "data" : ["message1"]
}

我得到的是

{
    "data" : []
}

有什么主意,为什么消费者直到写了一定数量的消息后才使用记录?

EDIT_1: 向消费者添加了props.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");属性,但没有任何效果。

1 个答案:

答案 0 :(得分:0)

在您手动调用此testConsumer.poll(Duration.ofMillis(100))时。您需要不断地从主题中汇集。就像在一个无限的while循环中一样。例如:

while (true) {
   Map records = consume();
   logger.debug("received records: {}", records);
}

看看这个链接:Kafka consumer