Java Kafka enable.auto.commit false与commitSync()结合使用
我遇到了一个场景,Java Kafka enable.auto.commit false与commitSync()结合使用,java,apache-kafka,Java,Apache Kafka,我遇到了一个场景,enable.auto.commit被设置为false。对于每个poll(),获得的记录都会卸载到threadPoolExecutor。而commitSync()是在上下文之外发生的。但是,我怀疑这是否是正确的处理方法,因为在我提交消息时,我的线程池可能仍然处理很少的消息 while (true) { ConsumerRecords < String, NormalizedSyslogMessage > records = consumer.poll(100);
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();
}
while(true){
ConsumerRecordsrecords=consumer.poll(100);
Date startTime=Calendar.getInstance().getTime();
对于(ConsumerRecordrecord:records){
NormalizedSyslogMessage normalizedMessage=record.value();
normalizedSyslogMessageList.add(normalizedMessage);
}
Date endTime=Calendar.getInstance().getTime();
long DurationInMilliesec=endTime.getTime()-startTime.getTime();
//在消息大小等于5000或超时>4000时执行进程线程
if(normalizedSyslogMessageList.size()==5000){
CorrelationProcessThread CorrelationProcessThread=applicationContext
.getBean(CorrelationProcessThread.class);
ListclonedNormalizedSyslogMessages=deepCopy(normalizedSyslogMessageList);
correlationProcessThread.SetNormalizedMessages(clonedNormalizedSyslogMessages);
taskExecutor.execute(correlationProcessThread);
normalizedSyslogMessageList.clear();
}
consumer.commitSync();
}
我想这里有几件事需要解决
首先是偏移量不同步-这可能是由以下任一原因造成的:
poll()
获取的消息数没有将normalizedSyslogMessageList
的大小设置为5000,则无论当前批消息是否已处理,commitSync()
仍将运行commitSync()
无论如何都会运行,以提交偏移量correlationProcessThread
在这里以一种“火而忘”的方式被调用,所以您不知道这些消息的处理将在何时完成,以便您能够安全地提交偏移量
以下是《卡夫卡权威指南》中的声明-
记住commitSync()将提交最新的
poll()返回的偏移量,因此请确保在
您已完成对集合中所有记录的处理,否则您将面临风险
丢失的消息
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点尤其难以修复,因为:
- 向池中的线程提供使用者引用基本上意味着多个线程试图访问一个使用者实例(提到了这种方法和问题——主要是Kafka使用者不具备线程安全性)李>
- 即使您尝试在提交偏移量之前使用
方法而不是submit()
中的executeService
获取处理线程的状态,您也需要对execute()
进行阻塞get()方法调用。因此,在多个线程中处理可能不会带来很多好处correlationProcessThread
- 根据使用者实例需要执行的处理中断使用者实例,并在同一线程或线程中执行处理
- 您可以探索在映射中维护消息偏移量的可能性(在处理它们时),然后提交这些特定偏移量()
我希望这能有所帮助。完全同意Lalit所提到的。目前,我正在经历同样的情况,我的处理在不同的线程中进行,消费者和生产者在不同的线程中进行。我使用了一个ConcurrentHashMap在生产者线程和消费者线程之间共享,它更新特定偏移量是否已被处理
ConcurrentHashMap<OffsetAndMetadata, Boolean>
ConcurrentHashMap
在使用者端,可以使用本地LinkedHashMap来维护从主题/分区消费记录的顺序,并在使用者线程本身中进行手动提交
LinkedHashMap<OffsetAndMetadata, TopicPartition>
LinkedHashMap
如果处理线程正在维护任何消耗的记录顺序,则可以参考以下链接。
在我的方法中需要提到的一点是,如果出现任何故障,数据都有可能被复制