kafka异步提交请求失败

时间:2019-03-08 13:19:38

标签: apache-kafka kafka-consumer-api

我观察到,卡夫卡消费者的滞后时间在运行数小时/天后突然开始增加。

检查日志后,我看到很多异常:

  

org.apache.kafka.clients.consumer.RetriableCommitFailedException:偏移提交失败,并出现可重试的异常。您应尝试重新提交最新消耗的偏移量。

我的ConsumerThread类:

public class ConsumerThread implements Runnable {
  private final KafkaConsumer<String, Map<String, Object>> consumer;
  public ConsumerThread(
    this.consumer = new KafkaConsumer<>(getConsumerConfig(kafkaConfiguration));
  }

  @Override
  public void run() {
    try {
      consumer.subscribe(topicList);

      while (true) {
        ConsumerRecords<String, Map<String, Object>> records =
            consumer.poll(Duration.ofMillis(kafkaConfiguration.getPollIntervalMs()));

        long startPerPoll = System.nanoTime();
        for (final ConsumerRecord<String, Map<String, Object>> record : records) {
            // message processing logic here
        }


        consumer.commitAsync((offsets, exception) -> {
            if (exception != null) {
              //log.error(exception.getMessage());
              log.info("exception while committing offset, consumerThread: {}, exception: {}", Thread.currentThread().getName(), exception);
              exception.printStackTrace();
            }
        });


      }
    } catch (Exception e) {
      // ignore for shutdown
      log.info("exception in run for consumerThread: {}", e);
    } finally {
      try {
        if (Objects.nonNull(consumer)) {
          consumer.commitSync();
        }
      } finally {
        if (Objects.nonNull(consumer)) {
          consumer.close();
        }
      }
    }
}

我的kafka配置:

groupId: cep-cg
autoCommitEnabled: false
sessionTimeoutMs: 30000
heartBeatIntervalMs: 10000
autoOffsetReset: latest
maxPollRecord: 250
maxPollIntervalMs: 180000
requestTimeoutMs: 240000
pollIntervalMs: 3000

我检查了关于stackoverflow的其他答案,并进行了一些调整,但似乎都无效。

我想知道的是:

  1. 任何人都可以解释为什么滞后会突然增加吗?

  2. 是否有很多commitAsync请求在代理上挂起,也许有一段时间(由代理上的某些配置定义),commitAsync请求开始失败?

  3. 假设消费者线程花了max.poll.interval.ms以上的时间来处理消息。在这种情况下,它将被踢出该组并触发重新平衡。现在,代理上所有待处理的commitAsync请求都因CommitFailedException而失败,因为该分区现在属于组中的其他某个使用者。在上面的代码中,使用者将摆脱无限循环,并将永远关闭。这是正确的方法吗?还是我应该抓住CommitFailedException并再次恢复循环以保持消费者的生命?

1 个答案:

答案 0 :(得分:0)

想象一下,我们发送了一个提交偏移量2000的请求。这是一个暂时的通信问题,因此代理从未获得该请求,因此也从未响应。与此同时, 我们处理了另一个批次并成功提交了偏移量3000。现在重试以前的批次失败的提交,并且例外情况下,它会显示相同的消息。在重新平衡的情况下,这将导致重复次数更多

A。滞后时间在增加

由于重新平衡的频率越来越高,因此消费者没有不断使用记录,而生产者却在不断产生记录。

B。 commitAsync请求超时

仅该组的活动成员可以提交偏移量。如果使用者在尝试提交偏移量时已被踢出组,则会抛出CommitFailedException

c。重新平衡

重新平衡开始时,使用者必须在会话超时到期之前完成其当前正在执行的所有处理,提交偏移量并重新加入该组。

我们应该强制使用ConsumerRebalanceListener并使用onPartitionsRevoked()提交偏移,然后再失去对分区的所有权以提交当前偏移。

max.poll.interval.ms max.poll.records 设置为一个相当低的值,同时也将session.timeout.ms保持为低,这样故障检测时间就不会出现不需要牺牲。

从commitSync()引发的

CommitFailedException。这样可以保证只有组中的活动成员才可以提交偏移量。如果使用者已被踢出该组,则其分区将被分配给另一个成员,该成员将提交自己的偏移量。