关于kafka的消费组模式,差了点相关资料,其中有一点提到:
一个主题下的分区不能小于消费者数量,即一个主题下消费者数量不能大于分区属,大了就浪费了
那么,如果我的消费者进程数大于分区数的话,会有什么现象了,接下来就做个实验试试
1、首先,创建一个3分区,主题名为test3
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic test3
2、编写生产者和消费者脚本,本人用的开发语言是php,demo例子可以参考文档,只要做一些小修改就可以了
附上文档地址:https://arnaud.le-blanc.net/php-rdkafka-doc/phpdoc/rdkafka.examples-high-level-consumer.html
生产者脚本
1 <?php
2
3 $objRdKafka = new RdKafka\Producer();
4 $objRdKafka->setLogLevel(LOG_DEBUG);
5 $objRdKafka->addBrokers("192.168.78.139:9092");
6
7 $oObjTopic = $objRdKafka->newTopic("test3");
8
9 // 从终端接收输入
10 $oInputHandler = fopen('php://stdin', 'r');
11
12 while (true) {
13 echo "\nEnter messages:\n";
14 $sMsg = trim(fgets($oInputHandler));
15
16 // 空消息意味着退出
17 if (empty($sMsg)) {
18 break;
19 }
20
21 // 发送消息
22 $oObjTopic->produce(RD_KAFKA_PARTITION_UA, 0, $sMsg);
23 }
24
25 echo "done\n";
26 ?>
消费者脚本
<?php
$conf = new RdKafka\Conf();
// Set a rebalance callback to log partition assignments (optional)
// 当有新的消费进程加入或者退出消费组时,kafka 会自动重新分配分区给消费者进程,这里注册了一个回调函数,当分区被重新分配时触发
$conf->setRebalanceCb(function (RdKafka\KafkaConsumer $kafka, $err, array $partitions = null) {
switch ($err) {
case RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS:
echo "Assign: ";
var_dump($partitions);
$kafka->assign($partitions);
break;
case RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS:
echo "Revoke: ";
var_dump($partitions);
$kafka->assign(NULL);
break;
default:
throw new \Exception($err);
}
});
// 配置groud.id 具有相同 group.id 的consumer 将会处理不同分区的消息,所以同一个组内的消费者数量如果订阅了一个topic, 那么消费者进程的数量多于 多于这个topic 分区的数量是没有意义的。
$conf->set('group.id', 'myConsumerGroup1');
//添加 kafka集群服务器地址(ip地址和端口替换成自己本地测试环境)
$conf->set('metadata.broker.list', '192.168.78.139:9092');
$topicConf = new RdKafka\TopicConf();
// Set where to start consuming messages when there is no initial offset in
// offset store or the desired offset is out of range.
// 'smallest': start from the beginning
//当没有初始偏移量时,从哪里开始读取
$topicConf->set('auto.offset.reset', 'smallest');
// Set the configuration to use for subscribed/assigned topics
$conf->setDefaultTopicConf($topicConf);
$consumer = new RdKafka\KafkaConsumer($conf);
// 让消费者订阅log 主题(topic替换成自己生成的)
$consumer->subscribe(['test3']);
while (true) {
$message = $consumer->consume(120*1000);
switch ($message->err) {
case RD_KAFKA_RESP_ERR_NO_ERROR:
var_dump($message);
break;
case RD_KAFKA_RESP_ERR__PARTITION_EOF:
echo "No more messages; will wait for more\n";
break;
case RD_KAFKA_RESP_ERR__TIMED_OUT:
echo "Timed out\n";
break;
default:
throw new \Exception($message->errstr(), $message->err);
break;
}
}
?>
3、开始试验
启4个消费者脚本,然后用生产者生成多个消息,进行观察
如上图所示。消费者2,3,4都能进行消费,而消费者1就只是挂着啥事都不干
接下来,试试kill掉其中一个消费者,比如消费者4,然后继续产生消息
这是,消费者1顶替了消费者4的位置,进行消息的消费
结论:当消费者总数大于分区数的话,多余的消费者进程会一直挂着,但是当某个消费者进程down掉的话,之前那些多余的消费者进程会顶替上来