点对点模式基于队列,类似于同一个消费者组中的数据,由生产者发送数据到分区,然后消费者拉取分区的消息进行消费,此时消息只能被同一个消费者组的消费者消费一次。
发布订阅模式模式就是 kafka 中的分区消息可以被不同消费者组的消费者消费。这就是一对多的广播模式应用。
当然,消费者组是一个逻辑的概念,通过客户端参数 group.id 来配置,默认值为空字符串。而消费者并不是逻辑的概念,它是真正消费数据的实体,可以是线程、也可以是一个机器。
好,明白了消费者与消费者组的概念,接下来我们正式打开 消费者客户端的潘多拉魔盒。
二、Kafka 消费者的应用
同样,消费者也是依赖于 Kafak 的客户端,正常的消费逻辑是下面几个步骤:
1、配置消费者客户端参数及创建相应的消费者实例
2、订阅主题
3、拉取消息并消费
4、提交消费位移
5、关闭消费者实例
这里的位移可能我们还不清楚是什么意思,别急,我们后面会讲到,先来看下一个典型的消费者它应该怎么写。
public class Consumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put(“bootstrap.servers”, “192.168.81.101:9092”);
props.put(“group.id”, “test”); //消费者组
props.put(“key.deserializer”, “org.apache.kafka.common.serialization.StringDeserializer”);
props.put(“value.deserializer”, “org.apache.kafka.common.serialization.StringDeserializer”);
KafkaConsumer
consumer.subscribe(Arrays.asList(“xiaolei2”));
while (true) {
ConsumerRecords
for (ConsumerRecord
System.out.printf(“offset = %d, key = %s, value = %s%n”, record.offset(), record.key(), record.value());
}
}
}
}
在创建消费者的时候,Kafka 有 4 个参数 是必填的,比生产者多了一个。
bootstrap.servers : 这个参数用来指定连接 Kafka 集群的 broker 地址列表,可以是单个地址,也可以用逗号分割填上 Kafka 集群地址。
key.deserializer 和 value. deserializer :因为消息发送的时候将key 和 value 进行序列化生成字节数组,因此消费数据的时候需要反序列化为原来的数据。
group.id : 消费者所在组的名称,默认值为 ”“,如果设置为空,则会抛出异常 Exception in thread “main” org.apache.kafka.common.errors.InvalidGroupIdException: To use the group management or offset commit APIs, you must provide a valid group.id in the consumer configuration. 复制代码
在创建出 consumer 之后,我们需要为它订阅相关的主题,一个消费者可以订阅一个或多个主题。这里可以使用两个 API
consumer.subscribe(Collection topics) :指明需要订阅的主题的集合;
consumer.subscribe(Pattern pattern) :使用正则来匹配需要订阅的集合。
对于它订阅的是个集合,我们也容易理解,Kafka 可以通过正则表达式 来匹配相关主题,例如下面的这样:
consumer.subscribe(Pattern.compile(“topic-.*”));
但是如果 consumer 重复定义的话,就以后面的为准,下面订阅的就是 xiaolei3 这个主题。
consumer.subscribe(Arrays.asList(“xiaolei2”));
consumer.subscribe(Arrays.asList(“xiaolei3”));
订阅完主题,我们讲讲它怎么定义分区。
直接订阅特定分区。
consumer.assign(Arrays.asList(new TopicPartition(“xiaolei2”,0)));
这里面使用了 assing 方法来订阅特定分区。那如果不知道有哪些分区怎么办呢?
可以使用 KafkaConsumer 的 partitionsFor() 方法用来查询指定主题的元数据信息。
下面这种实现:
consumer.assign(Arrays.asList(new TopicPartition(“xiaolei2”,0)));
ArrayList topicPartitions = new ArrayList<>();
List partitionInfos = consumer.partitionsFor(“xiaolei2”);
for (PartitionInfo partitionInfo : partitionInfos) {
topicPartitions.add(new TopicPartition(partitionInfo.topic(),partitionInfo.partition()));
}
consumer.assign(topicPartitions);
最后,Kafka 中的消费是基于拉取式的,消息的消费分两种,
一个是推送(push):服务端主动把消息发送给消费者,例如微信公众号文章的发送
一个是拉取(poll):消费者主动向服务端发起请求获取。
Kafka 只需要轮询 API 向服务器定时请求数据,一旦消费者订阅了主题,轮询就会处理所有的细节,例如发送心跳、获取数据、分区再平衡等。而我们则处理业务即可。
三、消费位移
对于 Kafka 的分区来说,它的每条消息都有唯一的偏移量,用来展示消息在分区中对应的位置,它是一个单调递增的整数。在 0.9 版本之后 Kafka 的偏移量是存储在 Kafka 的 _consumer_offsets 主题中。消费者在消费完消息之后会向 这个主题中进行 消费位移的提交。消费者在重新启动的时候就会从新的消费位移处开始消费消息。