kafka 消费者的消费策略以及再平衡实操案例2

一 kafka的消费策略

1 、一个 consumer group 中有多个 consumer 组成,一个 topic 有多个 partition 组成,现在的问题是, 到底由哪个 consumer 来消费哪个partition的数据
2 Kafka 有四种主流的分区分配策略: Range RoundRobin Sticky CooperativeSticky
可以通过配置参数 partition.assignment.strategy ,修改分区的分配策略。默认策略是 Range + CooperativeSticky Kafka 可以同时使用 多个分区分配策略。
3.策略判断参数

4.执行流程

1. 每个consumer都 发送JoinGroup请求

2.选出一个 consumer作为 leader
3.把要消费的 topic 情况 发送给leader 消费者
4. leader 会负 责制定消费方案
5. 把消费方案发给 coordinator
6. Coordinator 就把消费 方案下发给各个consumer
7.每个消费者都会和 coordinator 保持心跳( 默认 3s ),一旦超时 session.timeout.ms= 45s ),该消费者会被移除,并触发再平衡;或者消费者处理消息的过长(max.poll.interval.ms 5 分钟),也会触发再 平衡

二   Range分区策略

2.1 range分区策略

Range 是对每个 topic 而言的。 首先对同一个 topic 里面的 分区按照序号进行排序 ,并
消费者按照字母顺序进行排序
假如现在有 7 个分区, 3 个消费者,排序后的分区将会 是0,1,2,3,4,5,6 ;消费者排序完之后将会是 C0,C1,C2 。 例如,7/3 = 2 1 ,除不尽,那么 消费者 C0 便会多 消费 1 个分区。 8/3=2 2 ,除不尽,那么 C0 C1 分别多 消费一个。 通过 partitions /consumer 来决定每个消费者应该
消费几个分区。 如果除不尽,那么前面几个消费者将会多 消费 1 个分区。
分区分配策略之 Range
注意: 如果只是针对 1 topic 而言, C0 消费者多消费 1 个分区影响不是很大。但是如果有 N 多个 topic ,那么针对每 个 topic ,消费者 C0 都将多消费 1 个分区, topic 越多, C0 消 费的分区会比其他消费者明显多消费 N 个分区。
容易产生数据倾斜!

2.2 案例分析

1.修改主题 first 7 个分区。注意:分区数可以增加,但是不能减少。

bin/kafka-topics.sh --bootstrap-server  hadoop102:9092 --alter --topic first --partitions 7
2.复制 CustomConsumer 类,创建 CustomConsumer2。这样可以由三个消费者
CustomConsumer CustomConsumer1 CustomConsumer2 组成消费者组,组名都为“ test ”,
同时启动 3 个消费者。
3. 启动 CustomProducer 生产者,发送 500 条消息,随机发送到不同的分区。
说明: Kafka 默认的分区分配策略就是 Range + CooperativeSticky ,所以不需要修改策
4. 观看 3 个消费者分别消费哪些分区的数据。
0号消费者

 1号消费者

2号消费者

 分析:

1).停止掉 0 号消费者,快速重新发送消息, 然后观看结果(45s 以内,越快越好)。
1 号消费者:消费到 3 4 号分区数据。
2 号消费者:消费到 5 6 号分区数据。
0 号消费者的任务会 整体被分配 1 号消费者或者 2 号消费者。
说明: 0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需
要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行。

 2)45s 以后,再次重新发送消息观看结果

1 号消费者:消费到 0 1 2 3 号分区数据。
2 号消费者:消费到 4 5 6 号分区数据。
说明:消费者 0 已经被踢出消费者组,所以重新按照 range 方式分配。

三   RoundRobin分区策略

3.1 分区策略

RoundRobin 针对集群中 所有 Topic 而言 。 RoundRobin 轮询分区策略,是把 所有的 partition 和所有的 consumer 都列出来 ,然后 按照 hashcode 进行排序 ,最后 通过 轮询算法 来分配 partition 给到各个消费者。

 3.2 案例

1.修改之前的3个消费者,消费策略:依次在 CustomConsumerCustomConsumer1CustomConsumer2 三个消费者代 码中修改分区分配策略为 RoundRobin

 2.重启 3 个消费者,重复发送消息的步骤,观看分区结果。

消费者0:

消费者1:

 消费者2:

分析:

1)停止掉 0 号消费者,快速重新发送消息,然后观看结果(45s 以内,越快越好)。
1 号消费者:消费到 2 5 号分区数据
2 号消费者:消费到 3 、6、 0 号分区数据
0 号消费者的任务会 按照 RoundRobin 的方式,把数据轮询分成 1   、4 号分区数据,
分别由 1 号消费者或者 2 号消费者消费。
说明: 0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需
要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行
2) 45s 以后,再次重新发送消息观看结果。
1 号消费者:消费到 0 2 4 6 号分区数据
2 号消费者:消费到 1 3 5 号分区数据
说明:消费者 0 已经被踢出消费者组,所以重新按照 RoundRobin 方式分配。

 四   Sticky 以及再平衡

 4.1 粘性分区

粘性分区定义: 可以理解为分配的结果带有“粘性的”。即在执行一次新的分配之前, 考虑上一次分配的结果,尽量少的调整分配的变动,可以节省大量的开销。
粘性分区是 Kafka 0.11.x 版本开始引入这种分配策略, 首先会尽量均衡的放置分区
到消费者上面 ,在出现同一消费者组内消费者出现问题的时候,会 尽量保持原有分配的分
区不变化。

4.2 案例

设置主题为 first 7 个分区;准备 3 个消费者,采用粘性分区策略,并进行消费,观察
消费分配情况。然后再停止其中一个消费者,再次观察消费分配情况
1.修改分区分配策略为粘性。
注意: 3 个消费者都应该注释掉,之后重启 3 个消费者,如果出现报错,全部停止等 会再重启,或者修改为全新的消费者组。
2.使用同样的生产者发送 500 条消息。可以看到会尽量保持分区的个数近似划分分区
0号消费者

1号消费者

 2号消费者

 分析:

1 )停止掉 0 号消费者,快速重新发送消息,然后观看结果(45s 以内,越快越好)。
1 号消费者:消费到 2 5 3 号分区数据。
2 号消费者:消费到 4 6 号分区数据。
0 号消费者的任务会 按照粘性规则,尽可能均衡的随机分成 0 1 号分区数据,分别
1 号消费者或者 2 号消费者消费。
说明: 0 号消费者挂掉后,消费者组需要按照超时时间 45s 来判断它是否退出,所以需
要等待,时间到了 45s 后,判断它真的退出就会把任务分配给其他 broker 执行。
(2)45s 以后,再次重新发送消息观看结果
1 号消费者:消费到 2 3 5 号分区数据。
2 号消费者:消费到 0 1 4 6 号分区数据。
说明:消费者 0 已经被踢出消费者组,所以重新按照粘性方式分配。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于Java的Kafka生产者和消费者案例: **Kafka生产者案例:** ```java import java.util.Properties; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; public class KafkaProducerExample { public static void main(String[] args) throws Exception { String topicName = "test-topic"; String key = "test-key"; String value = "test-value"; Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ProducerRecord<String, String> record = new ProducerRecord<>(topicName, key, value); producer.send(record); producer.close(); } } ``` **Kafka消费者案例:** ```java import java.util.Collections; import java.util.Properties; import org.apache.kafka.clients.consumer.Consumer; 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; public class KafkaConsumerExample { public static void main(String[] args) throws Exception { String topicName = "test-topic"; String groupId = "test-group"; Properties props = new Properties(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); Consumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Collections.singletonList(topicName)); while (true) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) { System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value()); } } } } ``` 以上案例中,生产者将一条消息发送到名为“test-topic”的主题中,消费者订阅该主题并消费消息。请注意,这只是基本示例,您可以根据需要进行更改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值