java 多线程消费kafka

需求

现有500个Topic,每个Topic有8个分区,需要一直进行消费

问题

500个线程8个分区,可以为每个分区设置一个消费者消费吗

最好不
需要考虑服务器压力,以及kafka生产的速率
如果每个分区一个消费者,那么会建立4000个线程来同时消费,这样会压垮服务器
考虑到服务器压力,加入CPU核数为32核,因此可以设置固定的32线程,每个线程来执行不同的Topic的8个分区

为什么不为每个分区设置一个comsumer

这样会导致消费到的数据时间差值太大,可能生产者在源源不断的生产数据,这时候同个topic的8个分区,其中有些分区有消费者消费,导致数据已经到了偏移量50000的时候,其他同个topic的有些分区暂时没有消费者消费,当线程来消费的时候,才从10000开始消费,这样同个topic的数据消费差值太大

所以为了保证数据消费尽量的一致性需要同个消费者来消费同个topic

那么只设置32个线程,不是只能执行32个topic吗

是的,这里32个线程,相当于并行处理32个topic,其他几百个topic不执行了吗
要执行的,这里是需要考虑到生产者生产的效率的,如果这里消费者消费得快,清空了内存中的挤压数据,并且设置一个数据未拉取到时间,假设5s没拉取到数据,就释放该消费者,并让topic重新排队等到线程执行。这样就能保证其他topic也能执行了,数据多的topic可能会一直占用线程,数据少的可能就占用几分钟释放。

代码

import org.apache.kafka.common.TopicPartition;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;

public class SimplifiedKafkaMultiThreadConsumer {
   

    private static final String BOOTSTRAP_SERVERS = "localhost:9092";
    private static final String GROUP_ID = "dynamic-consumer-group";
    private static final String[] TOPICS = {
   "topic1", "topic2", "topic3", "topic4", /*... more topics ...*/};
    private static final int NUM_THREADS = 32;  // 假设 32 个线程
    private static final int PARTITIONS_PER_THREAD = 8; // 每个线程消费 8 个分区
    private static final long MAX_IDLE_TIME_MS = 5000;  // 如果 5 秒没有拉取到数据,则释放该线程

    // 使用 LinkedBlockingQueue 来作为任务队列
    private static final Queue<KafkaConsumerTask> taskQueue = new LinkedBlockingQueue<>();

    public static void main(String[] args) {
   
        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
        
        // 为每个 topic 创建任务,并将每个分区分配给线程
        for (String topic : TOPICS) {
   
            List<TopicPartition> partitions = new ArrayList<>();
            for (int i = 0; i < 8; i++) {
   
                partitions.add(new TopicPartition(topic, i));
            }

            for (int i = 0; i < partitions.size(); i += PARTITIONS_PER_THREAD) {
   
                int end = Math.min(i + PARTITIONS_PER_THREAD, partitions.size());
                List<TopicPartition> partitionsForThread = partitions.subList(i, end);
                taskQueue.add(new KafkaConsumerTask(partitionsForThread));
            }
        }

        // 提交所有任务
        while (!taskQueue.isEmpty()) {
   
            executorService.submit(taskQueue.poll());
        }

        executorService.shutdown();
    }

    // 每个消费者线程
    static class KafkaConsumerTask implements Runnable {
   
        private final List<TopicPartition> partitions;
        private long lastPollTime = System.currentTimeMillis(); // 上次拉取时间
        private long idleTime = 0; // 拉取不到数据的累计时长

        public KafkaConsumerTask(List<TopicPartition> partitions) {
   
            this.partitions = partitions;
        }

        @Override
        public void run() {
   
            Properties consumerProps = new Properties();
            consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值