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
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值