flink消费kafka数据如何保证kafka的分区与flink的消费线程一一对应?

1.flink程序总的消费线程是如何找见消费的对应kafka分区的?
核心代码如下:
public static int assign(KafkaTopicPartition partition, int numParallelSubtasks) {
int startIndex =
((partition.getTopic().hashCode() * 31) & 0x7FFFFFFF) % numParallelSubtasks;

    // here, the assumption is that the id of Kafka partitions are always ascending
    // starting from 0, and therefore can be used directly as the offset clockwise from the
    // start index
    return (startIndex + partition.getPartition()) % numParallelSubtasks;
}

根据topic名称的哈希值乘以31,再与0x7FFFFFFF按位进行与操作后,再与程序设置的并行度(如果算子单独设置并行度,则此并行度为source端并行度)进行取余操作,得到起始下标值。
起始下标拿到后,与程序消费的kafka当前分区编号求和后,再与程序并行度(也就是子任务的运行个数。如果算子单独设置并行度,则此并行度为source端并行度)进行取余操作,得到的就是程序中处理数据的具体线程编号。
这样就得到了,kafka分区编号和程序线程编号之间的映射关系。
2.kafka分区数和flink消费线程数的匹配
通过上面的分析我们知道了,flink消费线程是如何找到消费到的kafka某个分区中的数据的。但是在这里消费线程数和kafka分区数存在3种情况:消费线程数=kafka分区数,消费线程数>kafka分区数,消费线程数<kafka分区数。我们一一进行讨论。
消费线程数=kafka分区数
在这种情况下,通过第一部分我们知道,kafka分区和消费线程是一一对应的,每个消费线程只会去消费特定的kafka分区中的数据。kafka分区数:flink程序消费线程数=1:1,这样消费效率较高。但这样也可能会存在:kafka中的某个分区数据量较大,有数据倾斜的可能性,在消费线程中就会出现消费速率低下,甚至出现反压的情况。想要控制这种情况的出现,可以在将数据放入kafka中按照主键或者某个字段进行分区操作,这样尽可能的保证kafka中的数据不会存在倾斜的情况。
消费线程数>kafka分区数
这种情况就会出现,某几个线程会消费kafka分区中的数据,但是剩下的线程找不见分区中的数据,线程就会空转,浪费资源。这样也会导致一个问题,checkpoint做不了,可能会导致ck超时失败。ck失败,程序无法保存状态,程序就会失败宕机。这种情况应该禁止出现。
消费线程数<kafka分区数
这种情况下,某个线程可能会消费多个kafka分区中的数据。数据量较大时,出现数据倾斜的可能性会比较大,也可能因为消费速率导致出现反压进而影响程序的正常运行。这种情况也尽量避免。
综上所述,完美的情况是:kafka分区数:flink程序消费线程数=1:1,但可能受限于环境、网络等情况,也可以设置为kafka分区数:flink程序消费线程数=2:1。

posted @ 2022-09-06 14:47  贾彤  阅读(1052)  评论(0编辑  收藏  举报