【Flink】flink并行度与kafka分区(partition)设置

854 篇文章 860 订阅 ¥99.90 ¥299.90
本文详细探讨了Flink Consumer如何保证Kafka的每个分区由一个线程处理,当分区数与并行度不匹配时的处理方式,以及背后的取模运算原理。通过源码分析,揭示了Flink如何在不同并行度下分配Kafka Partition,并提供了相关拓展阅读资料。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1.概述

默认: 【Flink】FlinkConsumer是如何保证一个partition对应一个thread的

当分区与并行度不一样呢?

2.原理

采用取模运算;平衡 kafka partition与并行度关系。
计算公式
kafkaPartition mod 并行度总数 = 分配到并行度中的partition

例子:partition 个数为 6;并行度为 3

在这里插入图片描述

图示如下:

在这里插入图片描述

如上分析,如果并行度 大于 partition总数,那么多余的并行度分配不到 partition,该并行度也就不会有数据 如下图:3个kafka partition,flink设置4个并行度为例,编号为3的并行度将获取不到数据

在这里插入图片描述

3.源码分析

由于源码比较多,为了代码便于阅读,只抽取关键的代码

FlinkKafkaConsumerBase

public abstract class FlinkKafkaConsumerBase<T> extends RichParallelSourceFunction<T> implements
        CheckpointListener,
        ResultTypeQueryable<T>,
        CheckpointedFunction {
            
    /** 
      * The partition discoverer, used to find new partitions.
      * 分区 discover
      */
    private transient volatile AbstractPartitionDiscoverer partitionDiscoverer;
            
    /** 
      * Describes whether we are discovering partitions for fixed topics or a topic pattern.
      * topic 描述
      */
    private final KafkaTopicsDescriptor topicsDescriptor;
    
    //构造器
    public FlinkKafkaConsumerBase(
            List<String> topics,
            Pattern topicPattern,
            KafkaDeserializationSchema<T> deserializer,
            long discoveryIntervalMillis,
            boolean useMetrics) {
         // topicsDescriptor 创建
        this.topicsDescriptor = new KafkaTopicsDescriptor(topics, topicPattern);
        //...
    }
    
    @Override
    public void open(Configuration configuration) throws Exception {
        // create the partition discoverer
        this.partitionDiscoverer = createPartitionDiscoverer(
                topicsDescriptor,
                getRuntimeContext().getIndexOfThisSubtask(),//当前并行度 id
                getRuntimeContext().getNumberOfParallelSubtasks());//所有并行度总数
        this.partitionDiscoverer.open();
         //获取当前并行度 分配的 kafka partitions
         final List<KafkaTopicPartition> allPartitions = partitionDiscoverer.discoverPartitions();
         //...
    }
            
    /**
     * Creates the partition discoverer that is used to find new partitions for this subtask.
     *
     * @param topicsDescriptor Descriptor that describes whether we are discovering partitions for fixed topics or a topic pattern.
     * @param indexOfThisSubtask The index of this consumer subtask.
     * @param numParallelSubtasks The total number of parallel consumer subtasks.
     *
     * @return The instantiated partition discoverer
     */
    protected abstract AbstractPartitionDiscoverer createPartitionDiscoverer(
            KafkaTopicsDescriptor topicsDescriptor,
            int indexOfThisSubtask,
            int numParallelSubtasks);
        
}

AbstractPartitionDiscoverer : 该类为抽象类,有些方法实现在各个版本的kafka实现类中

public abstract class AbstractPartitionDiscoverer {
    
    /**
      * 当前并行度 id
      * Index of the consumer subtask that this partition discoverer belongs to.
      */
    private final int indexOfThisSubtask;

    /** 
      * 所有并行度总数
      * The total number of consumer subtasks.
      */
    private final int numParallelSubtasks;
    
    public List<KafkaTopicPartition> discoverPartitions() throws WakeupException, ClosedException {
    
        //获取 所有 partitions
        List<KafkaTopicPartition> newDiscoveredPartitions = 
            //各版本的kafka实现类中
            getAllPartitionsForTopics(topicsDescriptor.getFixedTopics());
        //移除掉不属于该并行度 中的 partition
        Iterator<KafkaTopicPartition> iter = newDiscoveredPartitions.iterator();
        KafkaTopicPartition nextPartition;
        while (iter.hasNext()) {
            nextPartition = iter.next();
            if (!setAndCheckDiscoveredPartition(nextPartition)) {
                iter.remove();
            }
        }
        
    }
    
    //判断是否是当前并行度的 任务
    public boolean setAndCheckDiscoveredPartition(KafkaTopicPartition partition) {
        if (isUndiscoveredPartition(partition)) {
            discoveredPartitions.add(partition);

            return KafkaTopicPartitionAssigner.assign(partition, numParallelSubtasks) == indexOfThisSubtask;
        }

        return false;
    }
}

KafkaTopicPartitionAssigner

public class KafkaTopicPartitionAssigner {
    //取模算法
    public static int assign(KafkaTopicPartition partition, int numParallelSubtasks) {
        int startIndex = ((partition.getTopic().hashCode() * 31) & 0x7FFFFFFF) % numParallelSubtasks;
        return (startIndex + partition.getPartition()) % numParallelSubtasks;
    }
}

链接:https://www.jianshu.com/p/777ca6cd71ee

7.拓展

【Flink】Flink kafka producer 分区策略 (flink写入数据不均匀 与 数据写入 分区无数据 )

flink写入kafka之默认序列化类和默认分区器

【Flink】flink并行度与kafka分区(partition)设置

【Flink】FlinkConsumer是如何保证一个partition对应一个thread的

Flink中,设置Flink Kafka并行度取决于所消费的Kafka主题的分区。如果只消费一个主题,则可以将并行度设置为主题的分区。例如,如果一个主题有4个分区,你可以将并行度设置为4。这样每个Flink任务将消费一个分区。 如果要消费多个主题,可以选择两种方式来设置并行度。第一种方式是将并行度设置为所有主题分区的总和。比如,如果有两个主题,一个主题有4个分区,另一个主题有6个分区,那么可以将并行度设置为10。这样每个Flink任务将消费多个主题的分区。 另一种方式是使用Robin的方式将据以round-robin的方式写入不同的Kafka分区。使用这种方式时,可以不用设置sink的并行度Flink会自动将据以round-robin的方式写入所有Kafka分区。 综上所述,Flink Kafka并行度设置与所消费的Kafka主题的分区有关。根据需要选择合适的并行度设置方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [flink kafka 消费以及生产并行度设置](https://blog.csdn.net/longlovefilm/article/details/117400809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [【Flink实战系列】Flink 消费 kafka 并行度设置多少合理(kafkapartitionFlink 的 subtask 对应关系...](https://blog.csdn.net/xianpanjia4616/article/details/108983357)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值