Java 消费者体验中的Kafka消息处理
我有一个消费者,它从一个主题中读取数据并生成一个线程进行处理。在一个时间点上,服务器中可以处理多条消息。应用程序遇到数据库超时,正在处理的所有消息都丢失。由于有多个线程轮询DB连接,应用程序抛出内存不足异常并停止运行。Java 消费者体验中的Kafka消息处理,java,apache-kafka,kafka-consumer-api,Java,Apache Kafka,Kafka Consumer Api,我有一个消费者,它从一个主题中读取数据并生成一个线程进行处理。在一个时间点上,服务器中可以处理多条消息。应用程序遇到数据库超时,正在处理的所有消息都丢失。由于有多个线程轮询DB连接,应用程序抛出内存不足异常并停止运行。 如何改进体系结构以消除数据丢失,即使消费者在未处理的情况下停机您应该在完成处理后通过提交偏移量至少进行一次处理。 i、 伊多 在您的任务完成后,线程将成功完成 请注意,您还需要通过将“enable.auto.commit”设置为false,配置使用者以自动停止发送偏移量 尽管你的
如何改进体系结构以消除数据丢失,即使消费者在未处理的情况下停机您应该在完成处理后通过提交偏移量至少进行一次处理。 i、 伊多 在您的任务完成后,线程将成功完成 请注意,您还需要通过将“enable.auto.commit”设置为false,配置使用者以自动停止发送偏移量
尽管你的消费者是幂等的,你还是需要小心。i、 e如果失败,并再次读取和处理相同的值,则不会影响结果。您应在完成处理后通过提交偏移量至少进行一次处理。 i、 伊多 在您的任务完成后,线程将成功完成 请注意,您还需要通过将“enable.auto.commit”设置为false,配置使用者以自动停止发送偏移量
尽管你的消费者是幂等的,你还是需要小心。i、 e如果失败,并再次读取和处理相同的值,则不会影响结果。您应该在从DB获得成功响应后提交偏移量 该问题与可用的数据库连接和线程有关。处理此问题的唯一方法是获取数据库连接,然后将数据库连接发送到线程 线程示例
public class ConsumerThreadHandler implements Callable {
private ConsumerRecord consumerRecord;
private Connection dataBaseConnection;
public ConsumerThreadHandler(ConsumerRecord consumerRecord,) {
this.consumerRecord = consumerRecord;
this.dataBaseConnection = dataBaseConnection;
}
@Override
public Object call() throws Exception {
// Perform all the data base related things
// and generate the proper response
return;
}
}
消费者代码
executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (final ConsumerRecord record : records) {
// Get database connection , Check untill get the connection or maintain the connection pool and based on available connection move next.
Future future=executor.submit(new ConsumerThreadHandler(record,dataBaseConnection));
if(future.isDone())
// Based on the proper response commit the offset
}
}
}
executor=newthreadpoolexecutor(numberOfThreads,numberOfThreads,0L,TimeUnit.毫秒,
新建LinkedBlockingQueue(),新建ThreadPoolExecutor.CallerRunPolicy());
while(true){
ConsumerRecords记录=consumer.poll(100);
用于(最终消费者记录:记录){
//获取数据库连接,选中直到获取连接或维护连接池,然后根据可用的连接移动下一步。
Future-Future=executor.submit(新的ConsumerThreadHandler(记录、数据库连接));
if(future.isDone())
//根据正确的响应提交偏移量
}
}
}
您可以浏览下面的简单示例
您应该在从DB获得成功响应后提交偏移量 该问题与可用的数据库连接和线程有关。处理此问题的唯一方法是获取数据库连接,然后将数据库连接发送到线程 线程示例
public class ConsumerThreadHandler implements Callable {
private ConsumerRecord consumerRecord;
private Connection dataBaseConnection;
public ConsumerThreadHandler(ConsumerRecord consumerRecord,) {
this.consumerRecord = consumerRecord;
this.dataBaseConnection = dataBaseConnection;
}
@Override
public Object call() throws Exception {
// Perform all the data base related things
// and generate the proper response
return;
}
}
消费者代码
executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (final ConsumerRecord record : records) {
// Get database connection , Check untill get the connection or maintain the connection pool and based on available connection move next.
Future future=executor.submit(new ConsumerThreadHandler(record,dataBaseConnection));
if(future.isDone())
// Based on the proper response commit the offset
}
}
}
executor=newthreadpoolexecutor(numberOfThreads,numberOfThreads,0L,TimeUnit.毫秒,
新建LinkedBlockingQueue(),新建ThreadPoolExecutor.CallerRunPolicy());
while(true){
ConsumerRecords记录=consumer.poll(100);
用于(最终消费者记录:记录){
//获取数据库连接,选中直到获取连接或维护连接池,然后根据可用的连接移动下一步。
Future-Future=executor.submit(新的ConsumerThreadHandler(记录、数据库连接));
if(future.isDone())
//根据正确的响应提交偏移量
}
}
}
您可以浏览下面的简单示例
感谢您的回答,以下情况的解决方案是什么:X和Y接收到2条消息。Y在X之后接收。X的处理失败,而Y成功。现在如果我提交Y的偏移量,X也会被提交。同意@Chris。在卡夫卡,通过向您的消费群体中添加更多的消费者,可以实现Parrellism。另外请注意,通过生成线程,您也失去了Kafka提供的订购保证。感谢您的回答,以下场景的解决方案是什么:X和Y接收到2条消息。Y在X之后接收。处理X失败,而Y成功。现在如果我提交Y的偏移量,X也会被提交。同意@Chris。在卡夫卡,通过向您的消费群体中添加更多的消费者,可以实现Parrellism。另外请注意,通过生成线程,您也失去了Kafka提供的订购保证。感谢您的回答,以下场景的解决方案是什么:X和Y接收到2条消息。Y在X之后接收。X的处理因任何原因失败(不仅仅是DB),而Y成功。现在,如果我提交Y的偏移量,X也将被提交。感谢您的回答,下面的场景的解决方案是什么:接收到2条消息X和Y。Y在X之后接收。X的处理由于任何原因(不仅仅是DB)失败,而Y成功。现在如果我提交偏移量Y,X也会被提交。值得注意的是,如果可能的话,避免产生线程来处理消息要简单得多。最好通过向组中添加额外的使用者(线程或单独的进程)并在轮询线程中进行处理来扩展,这样您就可以在每次轮询完成后安全地提交(或者只允许自动提交,在后续轮询期间提交以前的记录)值得注意的是,如果可能的话,避免产生线程来处理消息要简单得多。最好通过向组中添加额外的使用者(线程或单独的进程)并在轮询线程中进行处理来扩展,这样您就可以在每次轮询完成后安全地提交(或者只允许自动提交,在后续轮询期间提交以前的记录)