关于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掉的话,之前那些多余的消费者进程会顶替上来