大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。
Kafka是一个高吞吐量的分布式消息系统,它的消费者可以自动加入到消费者组中,并从主题的多个分区中接收消息。为了实现负载均衡和高可用性,Kafka使用Rebalance机制来重新分配分区,并确保每个消费者接收相等数量的分区。
在Kafka中,当消费者加入或离开消费者组时,或者某个消费者发生故障时,都可能会触发Rebalance操作。在Rebalance期间,Kafka会重新分配分区,并将它们分配给合适的消费者。Rebalance操作可能会导致消费者暂停接收消息,因为它们需要重新分配分区,重新连接和重新消费先前未消费的消息。
Kafka出现rebalance的原因:
- 消费者组成员发生变化:当有新的消费者加入或离开消费者组时,就会触发rebalance操作。例如,当有新的消费者启动时,它们将加入消费者组并接收新的分区分配。
- 分区分配策略发生变化:Kafka支持多种分区分配策略,例如Round-robin、Range、Sticky等。当分区分配策略发生变化时,就可能触发rebalance操作。
- 消费者健康状况发生变化:当某个消费者出现故障或长时间未发送心跳信号时,就可能被认为已经死亡并从消费者组中移除。这将导致其他消费者重新分配分区以平衡负载。(笔者在kafka exception一文中出现offset重复就是kafka触发了rebalance)
- 分区数目发生变化:当Kafka主题的分区数目发生变化时,就可能触发rebalance操作。例如,当管理员添加或删除分区时,就会重新分配消费者以反映新的分区数目。
- 消费者组ID发生变化:如果消费者组ID发生变化,例如消费者代码中的错误导致消费者组ID被更改,就可能触发rebalance操作。
举例说明:
public class ConsumerDemo {
private static final String TOPIC_NAME = "test";
private static final String GROUP_ID = "group1";
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", GROUP_ID);
props.put("auto.offset.reset", "earliest");
Consumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList(TOPIC_NAME), new MyConsumerRebalanceListener());
try {
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("partition = %d, offset = %d, key = %s, value = %s\n",
record.partition(), record.offset(), record.key(), record.value());
}
consumer.commitAsync();
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
consumer.close();
}
}
private static class MyConsumerRebalanceListener implements ConsumerRebalanceListener {
@Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
System.out.println("Partitions Revoked: " + partitions);
}
@Override
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
System.out.println("Partitions Assigned: " + partitions);
}
}
}
在上面的代码中,笔者创建了一个Kafka消费者,它使用“test”主题和“group1”消费者组。我们使用ConsumerRebalanceListener接口来处理Rebalance事件。在MyConsumerRebalanceListener类中,我们重写了onPartitionsRevoked()和onPartitionsAssigned()方法来处理Rebalance期间分区的变化。在onPartitionsRevoked()方法中,我们打印出要撤销的分区,在onPartitionsAssigned()方法中,我们打印出新分配的分区。这将帮助我们了解Rebalance过程中发生的分区重新分配。
在我们运行这个代码时,我们将看到在Rebalance期间打印出的日志消息,以及消费者重新连接并重新分配分区的过程。
写在最后
Kafka Rebalance是一个重要的机制,它确保了每个消费者接收相等数量的分区,从而实现了负载均衡和高可用性。在Rebalance期间,消费者需要重新分配分区,并重新连接和重新消费先前未消费的消息。为了更好地了解Rebalance机制的工作原理,我们可以使用ConsumerRebalanceListener接口来处理Rebalance事件,并在Rebalance期间打印出日志消息。