簡體   English   中英

Kafka Spring Batch Consumer - Commit single offset

[英]Kafka Spring Batch Consumer - Commit single offset

我在 SpringBoot 中遇到 Kafka 批處理監聽器的問題。

@Bean
public Map<String, Object> consumerConfigs() {
Map<String, Object> props = new HashMap<>();

props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, this.maxPollRecords);
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, this.autoOffsetReset);

props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, this.maxFetchBytesMaxPartition);
props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, this.maxFetchBytesMax);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer2.class);
props.put(ErrorHandlingDeserializer2.VALUE_DESERIALIZER_CLASS, ByteArrayDeserializer.class);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);

props.put(ConsumerConfig.RECEIVE_BUFFER_CONFIG, receiveBuffer);
props.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, heartbeatInterval);
props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, pollInterval);
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, sessionTimeout);
props.put(ConsumerConfig.FETCH_MIN_BYTES_CONFIG, minFetch);
props.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, maxWaitFetch);
return props;
}

@Bean
public DefaultKafkaConsumerFactory<String, byte[]> consumerFactory() {
    return new DefaultKafkaConsumerFactory<>(consumerConfigs());
}


@Bean
public KafkaListenerContainerFactory<?> kafkaListenerContainerFactory() {
    ConcurrentKafkaListenerContainerFactory<String, byte[]> factory = new ConcurrentKafkaListenerContainerFactory<>();

    try {
        factory.setConsumerFactory(consumerFactory());
        factory.getContainerProperties().setAckOnError(false);
        factory.setBatchListener(true);
        factory.getContainerProperties().setSyncCommits(false);
        factory.setBatchErrorHandler(new SeekToCurrentBatchErrorHandler());
        factory.getContainerProperties().setAckMode(AckMode.MANUAL_IMMEDIATE);
    } catch(Exception e) {
        logger.error("Error KafkaListenerContainerFactory: {}", e.getMessage());
    }

    return factory;
}

所以,這是@KafkaListener

@KafkaListener(autoStartup = "${kafka-startup}", groupId = "${kafka-group}", topics = "${queue}",
        containerFactory = "kafkaListenerContainerFactory", concurrency = "${concurrency}")
public void listen(@Payload List<byte[]> messages,
                   @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) List<String> keys,
                   @Header(KafkaHeaders.RECEIVED_PARTITION_ID) List<Integer> partitions,
                   @Header(KafkaHeaders.RECEIVED_TIMESTAMP) List<Long> timestamps,
                   @Header(KafkaHeaders.OFFSET) List<Long> offsets,
                   Acknowledgment ack) throws Exception {

    int indexQueue = new Random().nextInt(queues.size());

    for (int i = 0; i < messages.size(); i++) {
        //Do somethings
        ack.acknowledge();
    }
}

此解決方案對於我的問題不起作用,因為ack.acknowledge()批處理提交。 對於我的解決方案,我需要提交單個消息的偏移量。

我曾嘗試將KafkaConsumer<String, byte[]> consumerconsumer.commitAsync()一起使用,但情況是一樣的。 為了對其進行測試,腳本讀取了一批(由 3 個 mex 組成):在第三條消息中,腳本啟動了一個異常。

例如:消息 1 -> 偏移量 10; 消息 2 -> 偏移量 11,消息 3 -> 偏移量 12

腳本正在閱讀:

  • 消息 1(偏移量 10)-> 確定
  • 消息 2(偏移量 11)-> 確定
  • 消息 3(偏移量 12)-> 異常

在下一個循環中,腳本重新讀取偏移量為 10 的消息 1,但我預計消息 3 的偏移量為 12。

你有什么想法嗎? 你能幫我嗎?

謝謝

批處理偵聽器的Acknowledgment只能調用一次。

您現在可以(自 2.3 起)調用acknowledgment.nack(thisOneFailed, sleep);

參見https://docs.spring.io/spring-kafka/docs/current/reference/html/#committing-offsets

從 2.3 版開始, Acknowledgment接口有兩個額外的方法nack(long sleep)nack(int index, long sleep) 第一個與記錄偵聽器一起使用,第二個與批處理偵聽器一起使用。 為您的偵聽器類型調用錯誤的方法將引發 IllegalStateException。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM