Kafka enable.auto.commit false与commitSync()结合使用

时间:2018-08-23 17:51:45

标签: java apache-kafka

我遇到的情况是将enable.auto.commit设置为false。对于每个poll(),将获得的记录卸载到threadPoolExecutor中。 commitSync()发生在上下文之外。但是,我怀疑这是否是正确的处理方式,因为我提交消息时线程池可能仍在处理少量消息。

while (true) {
 ConsumerRecords < String, NormalizedSyslogMessage > records = consumer.poll(100);
 Date startTime = Calendar.getInstance().getTime();
 for (ConsumerRecord < String, NormalizedSyslogMessage > record: records) {
  NormalizedSyslogMessage normalizedMessage = record.value();
  normalizedSyslogMessageList.add(normalizedMessage);
 }
 Date endTime = Calendar.getInstance().getTime();
 long durationInMilliSec = endTime.getTime() - startTime.getTime();
 // execute process thread on message size equal to 5000 or timeout > 4000
 if (normalizedSyslogMessageList.size() == 5000) {
  CorrelationProcessThread correlationProcessThread = applicationContext
   .getBean(CorrelationProcessThread.class);
  List < NormalizedSyslogMessage > clonedNormalizedSyslogMessages = deepCopy(normalizedSyslogMessageList);
  correlationProcessThread.setNormalizedMessage(clonedNormalizedSyslogMessages);
  taskExecutor.execute(correlationProcessThread);
  normalizedSyslogMessageList.clear();
 }
 consumer.commitSync();
}

2 个答案:

答案 0 :(得分:0)

我想在这里要解决几件事。

首先是偏移不同步-这可能是由以下任一原因引起的:

  1. 如果poll()所获取的消息数量不等于normalizedSyslogMessageList到5000,则commitSync()仍将运行,而不管当前是否有这批消息是否已处理。

  2. 但是,如果大小达到5000,则因为处理是在单独的线程中完成的,所以主使用者线程将永远不会知道该处理是否已完成,但是... commitSync()无论如何都会运行提交偏移量。

第二部分(我相信这是您的实际关注/问题)-这是否是处理此问题的最佳方法。由于上面的第2点,我会说“否”,即correlationProcessThread在这里以即兴即忘的方式被调用,所以您不知道这些消息的处理将为您完成的安全地提交偏移量。

这是《卡夫卡权威指南》中的声明-

  

重要的是要记住,commitSync()将提交最新的   由poll()返回的偏移量,因此请确保您在之后调用commitSync()   您已处理完集合中的所有记录,否则您将承担风险   邮件丢失。

第2点尤其难以修复,因为:

  • 向消费者提供对池中线程的引用将基本上意味着多个线程试图访问一个消费者实例(This post提到了这种方法和问题-主要是,Kafka Consumer并非线程安全的) 。
  • 即使在submit()中使用execute()而不是ExecutorService方法来尝试在提交偏移量之前获取处理线程的状态,也需要进行阻塞对correlationProcessThread的get()方法调用。因此,通过在多个线程中进行处理,您可能不会获得很多好处。

用于修复此问题的选项

由于我不了解您的情况和确切要求,因此我只能提出概念性想法,但这可能值得考虑

  • 根据消费者需要进行的处理来打破消费者实例,并在同一线程或
  • 中进行处理
  • 您可以探索以下可能性:在地图中(在处理消息时以及在处理消息时)维护消息的偏移,然后提交这些特定的偏移(this method

我希望这会有所帮助。

答案 1 :(得分:0)

完全同意拉利特所说的话。目前,我正在经历相同的情况,即我的处理分别在不同的线程中进行,而消费者和生产者在不同的线程中进行。我使用了ConcurrentHashMap在生产者线程和使用者线程之间共享,从而更新了是否已处理特定偏移量。

ConcurrentHashMap<OffsetAndMetadata, Boolean>

在使用者方面,可以使用本地LinkedHashMap维护从主题/分区中消费记录的顺序,并在使用者线程本身中进行手动提交。

LinkedHashMap<OffsetAndMetadata, TopicPartition>

如果您的处理线程正在维护任何消耗的记录顺序,则可以参考以下链接。 Transactions in Kafka

在我的方法中要提到的一点是,万一发生任何故障,数据都将被复制。