Kafka 使用ExecutorService 进行消费

本文介绍了如何使用Apache Kafka结合Java的ExecutorService框架创建线程池,以处理大量消息并避免单线程性能瓶颈。文章详细阐述了从Kafka topic中获取消息,传递到线程池,以及工作线程的创建和执行过程。

前言:

         Apache Kafka 作为当下最常用消息中间件之一。给到我的需求是需要我们处理大量的消息(如果单线程处理过多消息会出现性能瓶颈)。

如何使用Java的ExecutorService框架来创建线程池处理大量消息?

      1.创建一个可以从topic中poll()消息后传递到线程池以进行进一步处理。

      2.创建工作线程,以执行每条消息的进一步处理。

1.topic消息传递到ThreadPoolExecutorService

/** kafka 消息处理*/
public class KafkaProcessor {
    private final KafkaConsumer<String, String> myConsumer;
    private ExecutorService executor;
    private static final Properties KAFKA_PROPERTIES = new Properties();
   
   //基础的kafka配置~
   static {
        KAFKA_PROPERTIES.put("bootstrap.servers", "localhost:9092
在 Java 中使用线程池消费 Kafka 消息是一种常见的优化手段,能够提升消费能力并有效利用系统资源。Kafka 消费者本身是单线程的,但可以通过将消息的消费逻辑交由线程池处理来实现多线程消费。以下是实现方法的详细说明。 ### 消费者线程模型设计 Kafka 消费者通常以单线程方式运行,调用 `poll()` 方法从 Kafka 分区中拉取消息。为了提高消费能力,可以在消费者线程中将消息分发给一个线程池,由线程池中的多个线程并发处理消息。 ### 线程池初始化 使用 `ExecutorService` 创建固定大小的线程池,线程数量可以根据 CPU 核数和任务处理时间进行调整。例如: ```java int threadPoolSize = Runtime.getRuntime().availableProcessors() * 2; ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize); ``` ### Kafka 消费者配置 Kafka 消费者的基本配置包括: ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "test-group"); props.put("enable.auto.commit", "false"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); ``` ### 消息拉取与分发 消费者通过 `poll()` 方法获取消息,然后将每条消息提交给线程池处理: ```java KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Arrays.asList("my-topic")); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { executorService.submit(() -> { // 处理消息的逻辑 System.out.printf("Thread %s consumed message with offset %d and value %s%n", Thread.currentThread().getName(), record.offset(), record.value()); }); } } ``` ### 提交偏移量策略 由于消息处理是异步的,偏移量的提交需要特别注意。推荐使用手动提交方式,确保只有在消息处理完成后才提交偏移量,避免数据丢失或重复消费: ```java consumer.commitSync(); ``` ### 性能优化与注意事项 - **线程池大小**:线程池的大小应根据任务的处理时间和系统资源进行调整。通常设置为 CPU 核数的 1~2 倍较为合理。 - **背压控制**:避免消费者拉取消息过快导致线程池积压过多任务,可以通过限制 `poll()` 的频率或使用有界队列控制任务数量。 - **异常处理**:在线程池中执行的任务应包含完整的异常处理逻辑,防止任务因异常而终止。 - **资源释放**:程序退出时应关闭消费者和线程池,确保资源正确释放: ```java consumer.close(); executorService.shutdown(); ``` ### 示例代码 以下是一个完整的示例代码: ```java import org.apache.kafka.clients.consumer.*; import org.apache.kafka.common.TopicPartition; import org.apache.kafka.common.serialization.StringDeserializer; import java.time.Duration; import java.util.Arrays; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class KafkaMultiThreadConsumer { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "test-group"); props.put("enable.auto.commit", "false"); props.put("key.deserializer", StringDeserializer.class.getName()); props.put("value.deserializer", StringDeserializer.class.getName()); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Arrays.asList("my-topic")); int threadPoolSize = Runtime.getRuntime().availableProcessors() * 2; ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize); try { while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { executorService.submit(() -> { System.out.printf("Thread %s consumed message with offset %d and value %s%n", Thread.currentThread().getName(), record.offset(), record.value()); // 模拟消息处理耗时 try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } // 手动提交偏移量 consumer.commitSync(); } } finally { consumer.close(); executorService.shutdown(); } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值