kafka消费者分区分配再平衡策列

360 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

kafka消费者消费分区的分配策略

独立消费者(不订阅分区)

消费者消费指定topic主题下的所有分区的数据。

在消费者 API 代码中必须配置消费者组 id。命令行启动消费者不填写消费者组id 会被自动填写随机的消费者组 id。

properties.put(ConsumerConfig.GROUP_ID_CONFIG, "test");

        // 2 订阅主题 first
        ArrayList<String> topics = new ArrayList<>();
        topics.add("first");
        kafkaConsumer.subscribe(topics);
​
        // 3 消费数据
        while (true){
​
            ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(Duration.ofSeconds(1));
​
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
                System.out.println(consumerRecord);
            }
​
            kafkaConsumer.commitAsync();
        }

独立消费者(订阅分区)

通过TopicPartition对象指定消费者消费哪个topic下的哪一个分区内容。

        // 组id
        properties.put(ConsumerConfig.GROUP_ID_CONFIG,"test");
        // 1 创建一个消费者
        KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);
        // 2 订阅主题对应的分区
        ArrayList<TopicPartition> topicPartitions = new ArrayList<>();
        topicPartitions.add(new TopicPartition("first",0));
        kafkaConsumer.assign(topicPartitions);
        // 3 消费数据
        while (true){
            ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(Duration.ofSeconds(1));
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
                System.out.println(consumerRecord);
            }
        }

消费者组

创建三个消费者,设置他们的组id相同,他们就会自动归档到一个消费者,然后通过消费者的方式进行消费。

分区的分配以及再平衡

一个消费者组由多个消费者组成,一个主题由多个分区组成,如何来保证哪个消费者消费哪个分区的数据。

kafka的主流分区分配有:Range、RoundRobin、Sticky、CooperativeSticky。 可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略。

Range分区再平衡

1、Range是针对与每一个topic来讲

2、首先会对topic按照分区序号排序和对消费者按照字母顺序排序

3、用分区数/消费者数来决定每个消费者应该消费几个分区。如果除不尽前面的几个消费者会分别多多消费一个分区。

4、如果topic的数量过多,除不尽的情况也比较多,那么排序在前面的消费者会消费更多的分区,造成数据倾斜。

例如,7/3 = 2 余 1 ,除不尽,那么 消费者 C0 便会多消费 1 个分区。 C0消费0,1,2分区,C1消费3,4分区,C2消费5,6分区。8/3=2余2,除不尽,那么C0和C1分别多消费一个。顺序固定。

1666254632687.png

停掉消费者C0,在45秒内再次发送消息,C0消费者的任务会被整体的划分到1号消费者或者2号消费者。

原因:每个消费者都会和coordinator保持心跳(默认3s),一旦超时(session.timeout.ms=45s),该消费者会被移除,并触发再平衡;或者消费者处理消息的过长(max.poll.interval.ms5分钟),也会触发再平衡。

45秒后再次发送消息:会触发再平衡策略即1号消费者消费:0,1,2,3;2号消费者消费4,5,6

RoundRobin分区再平衡

1、RoundRobin是针对所有的topic来讲

2、把所有的topic的分区和消费者都列出来,根据hashCode排序。最后采用轮询的方式把分区分配到具体的消费者。

1666341473366.png

停掉消费者C0,在45秒内再次发送消息,把数据轮询分成 0 、6 和 3 号分区数据,分别由 1 号消费者或者 2 号消费者消费。(不是整体给某一个消费者

当C0退出后,会再次轮询分配即0号分区给1号消费者,3号分区给2号消费者,6号分区给再给一号消费者。

45秒后再次发送消息:会触发再平衡策略即1号消费者消费:0,2,4,6;2号消费者消费1,3,5.

Sticky 以及再平衡

粘性分区是再执行分区分配时候会考虑前一次的分配结果,尽量少的调整分配的变动,来节省开销。

例如:七个分区、三个消费者。

均匀随机的消费:7处于3等于2余数1,则每一个会尽量分配两个,然后还有一个会多个分区消费。

比如有两个消费者消费两个分区:但是他们每次启动消费的分区数都不相同,与Range不同的时每次消费的都随机。

一开始

C0:0,1;

C1:2,5,3;

C2:4,6

停掉消费者C0,在45秒内再次发送消息,把数据轮询分成0,1 号分区数据,分别由 1 号消费者或者 2 号消费者消费。(不是整体给某一个消费者)。

当C0退出后C1多消费10号分区,C2多消费1号分区。

45秒后再次发送消息:会触发再平衡策略即1号消费者消费:2、3、5;2号消费者消费0、1、4、6。