如果未调用commitSync(),如何避免poll()检索相同的消息

时间:2019-01-02 12:52:59

标签: apache-kafka kafka-consumer-api

我对poll()的预期行为有些困惑。在我的应用中,如果processLogic()有效,那么我应该手动提交偏移量,以便在调用下一个poll()时,我确实会收到新消息。

processLogic()引发错误时发生问题。我设置使用者以寻求在处理期间失败的偏移量。在下一个poll()上,它再次收到相同的消息。(按照我命令消费者将偏移量手动重置到该位置的正确行为)想象一下它工作正常并且还调用了doCommitSync()。

意外的行为发生在以下poll()中。它应该接收新消息,但仍会检索最后一条消息,从而导致再次调用processLogic()函数和doCommitSync()。在doCommitSync()期间,它还会引发以下错误:

  

无法完成提交,因为该组已经重新平衡并已将分区分配给另一个成员。这意味着后续调用poll()之间的时间比配置的max.poll.interval.ms更长,这通常意味着轮询循环在消息处理上花费了太多时间。您可以通过增加会话超时或通过使用max.poll.records减小poll()中返回的批处理的最大大小来解决此问题。

我的消费者配置:

enable.auto.commit=false

isolation.level=read_committed

auto.offset.reset=latest

public void runConsumer() {
    Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));

    try {
      consumer.subscribe(topics);

      while (!closed.get()) {

        processedStatus.set(false);

        final ConsumerRecords<String, String> consumedRecords = consumer.poll(numRecords);
        if (!consumedRecords.isEmpty()) {
          StreamSupport.stream(consumedRecords.spliterator(), false)
            .map(ConsumerRecord::value)
            .forEach(record -> {
              try {
                processLogic(); //do some logic which can fail
                processedStatus.set(true);
              } catch (Exception e) {
                logger.error("Error applying action: " + record.getUuid(), e);
              }
              if (processedStatus.get()) {
                doCommitSync();
              } else {
                consumer.seek(new TopicPartition(recordTopic, recordPartition), recordOffset);
              }
            });
        }
      }
    } catch (WakeupException e) {
      logger.error("Kafka Consumer wakeup exception");
    } finally {
      alertConsumer.close();
      shutdownLatch.countDown();
    }

0 个答案:

没有答案