多线程消费KafkaDemo

这是一段基于Java开发的Kafka消费者代码。在该代码中,我们使用了多线程机制、线程池和多个消费线程来同时消费Kafka中的消息。具体实现步骤如下:

  1. 在KafkaConsumerExample构造函数中,传入了Kafka主题、Kafka服务器地址、消费者组ID和消费线程数等参数;
  2. 在consume()方法中,首先配置了Kafka消费者属性,并创建了KafkaConsumer实例;
  3. 然后订阅Kafka主题,并创建线程池;
  4. 接下来使用consumer.poll()方法从Kafka中拉取消息;
  5. 针对每一条消息,创建一个消费线程,通过线程池来处理消费线程;
  6. 最后,关闭线程池和Kafka消费者。

在该消费者中,消费线程实现了Runnable接口,在其run()方法中实现了消费者实际的逻辑,通过调用ConsumerRecord.value()方法来获取消息。消费者逻辑可以根据具体需求进行实现。

package com.controller;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.*;

public class KafkaConsumerExample {

    private final String topic;
    private final String bootstrapServers;
    private final String groupId;
    private final int numThreads;

    public KafkaConsumerExample(String topic, String bootstrapServers, String groupId, int numThreads) {
        this.topic = topic;
        this.bootstrapServers = bootstrapServers;
        this.groupId = groupId;
        this.numThreads = numThreads;
    }

    public void consume() {
        // 配置 Kafka 消费者属性
        Properties props = new Properties();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);

        // 创建 Kafka 消费者实例
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singleton(topic));

        // 创建线程池
//        ExecutorService executor = Executors.newFixedThreadPool(numThreads);

        // 获取当前机器的 CPU 核心数
        int corePoolSize = Runtime.getRuntime().availableProcessors();

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                corePoolSize * 2,
                10L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());

//        ThreadPoolExecutor(
//            int corePoolSize, // 线程池核心线程数,即初始化时的线程数,达到核心线程数后会将任务放入任务队列中等待处理,默认情况下即使有空闲线程也会将任务加入到队列中
//            int maximumPoolSize, // 线程池最大线程数,当任务队列已满并且当前线程数小于 maximumPoolSize 时,会创建新的线程来处理任务
//            long keepAliveTime, // 线程池中线程空闲时间的上限,超过这个时间的空闲线程将会被终止,直到线程池中的线程数减少到 corePoolSize 为止
//            TimeUnit unit, // keepAliveTime 的时间单位,一般设置为 TimeUnit.SECONDS 或 TimeUnit.MILLISECONDS
//            BlockingQueue workQueue, // 任务队列,用于存储等待执行的任务,常见的有 ArrayBlockingQueue、LinkedBlockingQueue 和 SynchronousQueue 等,具体选择根据实际情况决定
//            ThreadFactory threadFactory, // 创建线程的工厂,常用的是 Executors.defaultThreadFactory(),也可以自己实现 ThreadFactory 接口来自定义线程的名称、线程组等属性
//            RejectedExecutionHandler handler // 当线程池已满,并且等待队列已满,无法接收新任务时的拒绝策略,常见的有 AbortPolicy(抛出 RejectedExecutionException)、CallerRunsPolicy(由调用线程处理)、DiscardOldestPolicy(丢弃等待队列最旧的任务)和 DiscardPolicy(直接丢弃新任务)等
//        )

        try {
            while (true) {
                // 从 Kafka 中拉取消息
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));

                // 创建并执行消费线程
                for (ConsumerRecord<String, String> record : records) {
                    executor.submit(new ConsumerThread(record));
                }
            }
        } finally {
            // 关闭线程池和 Kafka 消费者
            executor.shutdown();
            consumer.close();
        }
    }

    private static class ConsumerThread implements Runnable {
        private final ConsumerRecord<String, String> record;

        public ConsumerThread(ConsumerRecord<String, String> record) {
            this.record = record;
        }

        @Override
        public void run() {
            // 消费者业务逻辑
            System.out.printf("消费者线程 %s 消费了消息:%s%n", Thread.currentThread().getName(), record.value());
        }
    }

    public static void main(String[] args) {
        String topic = "test-topic";
        String bootstrapServers = "localhost:9092";
        String groupId = "test-group";
        int numThreads = 3;

        KafkaConsumerExample consumerExample = new KafkaConsumerExample(topic, bootstrapServers, groupId, numThreads);
        consumerExample.consume();
    }
}

你可能感兴趣的:(kafka,java,大数据)