Kafka集群生产/消费的负载均衡(Rebalance)测试

基于Kafka客户端的高级API,配合zookeeper的使用,可以有效的实现Kafka集群的Rebalance,提高生产环境下的健壮性。本文使用librdkafka(https://github.com/edenhill/librdkafka) 提供的高级API来实现生产/消费,作为测试的基础。

生产者的负载均衡
对于同一个Topic的不同Partition,Kafka会尽力将这些Partition分布到不同的Broker服务器上,这种均衡策略实际上是基于Zookeeper实现的。在一个Broker启动时,会首先完成Broker的注册过程,并注册一些诸如“有哪些可订阅的Topic”之类的元数据信息。生产者启动后也要到zookeeper下注册,创建一个临时节点来监听Broker服务器列表的变化。由于在Zookeeper下Broker创建的也是临时节点,当Brokers发生变化时,生成者可以得到相关的通知,从改变自己的Broker list。其他的诸如Topic的变化以及Broker和Topic的关系变化,也是通过Zookeeper的这种Watcher监听实现的。
在生产中,必须指定topic;但是对于partition,有两种指定方式:

  1. 明确指定partition(0-N),则数据被发送到指定partition
  2. 设置为RD_KAFKA_PARTITION_UA,则kafka会回调partitioner进行均衡选取,partitioner方法需要自己实现。可以轮询或者传入key进行hash。未实现则采用默认的随机方法rd_kafka_msg_partitioner_random随机选择。

消费者的负载均衡
Kafka具有消费分组的概念,某个Topic的某个partition只能由一个Consumer group中的一个Consmer消费。但如果两个Consmer不在同一个Consumer group,那么他们是可以同时消费某Topic的同一个partition的。
对于某些低级别的API,Consumer消费时必须制定topic和partition,这显然不是一种很好的均衡策略。基于高级别的API,Consumer消费时只需制定topic,借助zookeeper可以根据partition的数量和consumer的数量做到均衡的动态配置。
消费者在启动时会到zookeeper下以自己的conusmer-id创建临时节点/consumer/[group-id]/ids/[conusmer-id],并对/consumer/[group-id]/ids注册监听事件,当消费者发生变化时,同一group的其余消费者会得到通知。当然,消费者还要监听broker列表的变化。librdkafka通常会将partition进行排序后,根据消费者列表,进行轮流的分配。消费者负载均衡中涉及的更重要的一点还有如何动态的维护partition的offset,因为消费者可能是变化的,而offset需要由comsumer来维护,librdkafka是借助zookeeper和消费者队列实现的,具体可以查看librdkafka的实现源码。(ps: Kafka已推荐将consumer的位移信息保存在Kafka内部的topic中,即__consumer_offsets(/brokers/topics/__consumer_offsets),并且默认提供了kafka_consumer_groups.sh脚本供用户查看consumer信息(sh kafka-consumer-groups.sh –bootstrap-server * –describe –group *)。在当前版本中,offset存储方式要么存储在本地文件中,要么存储在broker端, 具体的存储方式取决”offset.store.method”的配置,默认是存储在broker端)

Rebalance测试
下面基于librdKafka实现的C/C++客户端(0.9版本及以上),
测试Kafka集群的负载均衡。
测试环境及方法:

  • 三个broker通过zookeeper组成的集群;
  • 每个Topic默认三个分区,每个分区默认只有一个副本;
  • 通过增减生产者、消费者、broker来观察生产/消费的变化

1.配置kafka集群
由于条件有限,在同一个机器上启动三个broker来模拟kafka集群,三个broker使用另外安装的同一个zookeeper服务(实际集群中,每个broker通常在不同的机器上,也会使用不同host的zookeeper)
zookeeper的安装和启动并不复杂,在此略过。

cd /home/kafka/config
//准备三份用于启动kafka服务的配置
cp server.properties server-0.properties
cp server.properties server-1.properties
cp server.properties server-2.properties
三份配置中都要修改以下
broker.id=0(三个配置中分别修改为0,1,2)
port=9092(三个配置中分别修改为9092,9093,9094)
log.dirs=/tmp/kafka-logs-0(三个配置中分别修改为/tmp/kafka-logs-0,/tmp/kafka-logs-1,/tmp/kafka-logs-2)
num.partitions=3 (都设置为3,即每个topic默认三个partition)

2.测试
生产消费的负载均衡
启动三个broker:修改完配置后,开启三个shell窗口,分别启动三个broker
kafka/bin/kafka-server-start.sh server-X.properties
启动日志

...
[2017-02-19 20:38:39,766] INFO Kafka version : 0.10.1.1 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:38:39,766] INFO Kafka commitId : f10ef2720b03b247 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:38:39,775] INFO [Kafka Server 0], started (kafka.server.KafkaServer)

...
[2017-02-19 20:39:12,628] INFO Kafka version : 0.10.1.1 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:39:12,629] INFO Kafka commitId : f10ef2720b03b247 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:39:12,632] INFO [Kafka Server 1], started (kafka.server.KafkaServer)

...
[2017-02-19 20:42:18,809] INFO Kafka version : 0.10.1.1 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:42:18,809] INFO Kafka commitId : f10ef2720b03b247 (org.apache.kafka.common.utils.AppInfoParser)
[2017-02-19 20:42:18,812] INFO [Kafka Server 2], started (kafka.server.KafkaServer)

启动两个producer,创建名为xyz的topic,根据配置,该topic默认有3个partition:

[root@localhost producer]# ./producer 
Current RdKafka-ver:0.9.4-pre1
% Created producer rdkafka#producer-1
kafka的broker的日志变化分别是
//broker-0,名为xyz的topic的partition-2被分别到broker-0
[2017-02-19 20:45:17,268] INFO Partition [xyz,2] on broker 0: No checkpointed highwatermark is found for partition [xyz,2] (kafka.cluster.Partition)
//broker-1,名为xyz的topic的partition-0被分别到broker-1
[2017-02-19 20:45:17,325] INFO Partition [xyz,0] on broker 1: No checkpointed highwatermark is found for partition [xyz,0] (kafka.cluster.Partition)
broker-2,名为xyz的topic的partition-1被分别到broker-2
[2017-02-19 20:45:17,001] INFO Partition [xyz,1] on broker 2: No checkpointed highwatermark is found for partition [xyz,1] (kafka.cluster.Partition)
在/tmp/kafka-logs-[*]的变化也可以印证这一点

依次启动三个consumer:

//启动1台时,该消费者负责消费所有的3个partition
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[0], xyz[1], xyz[2],

//启动2台时,会触发消费者的负载均衡
//consumer-1
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[0], xyz[1], xyz[2], 
RebalanceCb: Local: Revoke partitions: xyz[0], xyz[1], xyz[2], 
RebalanceCb: Local: Assign partitions: xyz[0], xyz[1],

//consumer-2
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[2],

//启动3台时,会再次触发消费者的负载均衡
//consumer-1
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[0], xyz[1], xyz[2], 
RebalanceCb: Local: Revoke partitions: xyz[0], xyz[1], xyz[2], 
RebalanceCb: Local: Assign partitions: xyz[0], xyz[1], 
RebalanceCb: Local: Revoke partitions: xyz[0], xyz[1], 
RebalanceCb: Local: Assign partitions: xyz[0],

//consumer-2
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[2], 
RebalanceCb: Local: Revoke partitions: xyz[2], 
RebalanceCb: Local: Assign partitions: xyz[1],

//consumer-3
[root@localhost consumer]# ./consumer 
Current RdKafka-ver:0.9.4-pre1
RebalanceCb: Local: Assign partitions: xyz[2],

当依次关闭consumer时,同样会触发类似的rebalance,再次不一一演示
使用两个producer轮流向topic-xyz发送消息,三个消费者会大致消费相同的消息数目

broker的均衡
如果此时关掉一个broker,那么所以的消费者和生产者客户端都会收到如下的提示

2017-02-19 21:06:02.206: LOG-3-FAIL: [thrd:localhost:9094/bootstrap]: localhost:9094/bootstrap: Connect to ipv4#127.0.0.1:9094 failed: Connection refused
2017-02-19 21:06:02.206: ERROR (Local: Broker transport failure): localhost:9094/bootstrap: Connect to ipv4#127.0.0.1:9094 failed: Connection refused
在此之后,producer发送的消息将不会被发送host为localhost:9094的broker;如果该broker又恢复了,那么producer和consumer都会在此连接上该服务,因为他们都听过zookeeper监听着broker的变化

PS:
a.在本文的情况下(一个topic只有三个partition),如果启动4个consumer了?
由于只有3个partition,那么最后会有一个consumer无法消费

b.Rebalance后的消费者的从哪儿开始消费了?
offset由客户端和zookeeper通过consumer队列维护全局的变化


  1. 倪超.从Paxos到Zookeeper分布式一致性原理与实践.电子工业出版社,2015.
  2. librdkafka问题总结.http://blog.csdn.net/lybingo/article/details/52808192?locationNum=1&fps=1
### 回答1: Kafka使用Rebalance机制来确保消费者群组中的消费消费相同数量的分区,并确保消费者在分区分配发生更改时能够正确地处理它们。 当消费者加入或离开群组时,Kafka会触发Rebalance过程。在Rebalance过程中,Kafka会重新分配分区以确保每个消费者都消费相同数量的分区。Rebalance的过程可以分为两个阶段: 1. Revoke阶段:在此阶段,Kafka会将消费者正在消费的所有分区的控制权从消费者手中收回。这样可以确保在Rebalance期间不会有任何数据丢失。 2. Assign阶段:在此阶段,Kafka会重新分配分区以确保每个消费者都消费相同数量的分区。Kafka会确保在分配分区时考虑消费者的偏移量,以确保不会重复消费数据。 总的来说,Kafka的Rebalance机制是一种非常强大和可靠的机制,可以确保消费者群组中的消费消费相同数量的分区,并确保在分区分配发生更改时能够正确地处理它们。 ### 回答2: Kafka的rebalance机制是指在消费者组中添加或移除一个消费者时,Kafka如何重新分配分区给消费者。 当有新的消费者加入消费者组时,Kafka会根据分区的数量和消费者组的消费者数量来重新分配分区。Kafka首先计算出每个消费者应该处理的分区数量,然后将剩余的分区平均分配给所有的消费者。这样可以使得每个消费者处理大致相等的负载。 当有消费者离开消费者组时,Kafka会将该消费者所处理的分区重新分配给其他消费者。重新分配分区的策略有两种:Range策略和Round-robin策略。Range策略会将离开的消费者处理的分区范围平均分配给其他消费者。Round-robin策略会将离开的消费者处理的分区轮流分配给其他消费者。 在进行rebalance时,Kafka会暂停消费者读取消息,待分配完成后再继续消费。这样可以确保在分配过程中不会丢失消息。而在消费者组中,每个消费者都会维护一个偏移量,用于记录自己已消费的消息的位置。因此,消费者在重新分配分区后,可以继续从之前的偏移量处开始消费消息,避免重复消费。 总之,Kafka的rebalance机制可以保证消费者组中的消费者具有相对均衡的负载,并能够在分区重新分配时保证消息的连续性与一致性。这个机制在Kafka集群中起到了重要的作用,保证了高可用性和负载均衡的特性。 ### 回答3: Kafka的Rebalance机制是指在消费者组中加入或退出一个消费者时,Kafka自动重新分配消费者与消费者之间的Topic分区。这个机制的目的是保证消费者组内的负载均衡,确保每个消费者处理大致相同数量的消息。 当一个消费者加入或退出消费者组时,Rebalance机制会触发一个重新分配分区的过程。这个过程包括以下几个步骤: 1. 消费者加入或退出:当有一个消费者加入消费者组时,或者有一个消费者退出消费者组时,Kafka会进行重新分区。加入消费者组的消费者将被分配新的分区,而退出消费者组的消费者的分区将被重新分配给其它消费者。 2. 再均衡协调者:Kafka集群中会有一个特殊的角色,称为再均衡协调者。这个角色负责协调消费者组的再均衡过程。它会与消费者组中的每个消费者进行通信,以决定每个消费者应该被分配哪些分区。 3. 再均衡算法:再均衡协调者使用一种算法来决定分配给每个消费者的分区。这个算法要考虑分区的负载均衡,保证每个消费者处理大致相同数量的消息。具体的算法可以是Round Robin轮询、Range Range、Sticky等。 4. 分区指派:再均衡协调者完成分区的指派后,将结果通知给每个消费者。消费者根据指派结果来分配并处理属于它们的分区。 总之,Kafka的Rebalance机制在消费者组中加入或退出一个消费者时,自动进行分区的重新分配,以保证负载均衡消费者的高可用性。这个机制可以确保每个消费者处理大致相同数量的消息,提高整个消费者组的吞吐量和效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值