Kafka基础-消费者读取消息

下文介绍如何使用Java从Kafka订阅和读取消息,它和从其它消息系统读取消息有点不同,涉及到一些独特的概念。所以我们要先了解这些概念:

1. Kafka消费者概念

1.1 消费者和消费者组

当你只有一个消费者而且生产者发送消息的速率比消费者读取消息的速率要快的时候,处理新消息就会造成延时,显然需要配置多个消费者去读取消息。Kafka的消费者是消费者组的一部分,当多个消费者订阅一个topic并属于同一个消费者组时,该组中的每个消费者都将会接收这个topic不同分区的消息。

下图Topic T1有4个分区,消费者组G1只有1个消费者C1,那么G1订阅T1的时候,C1会从所有分区读取消息。

如果添加一个消费者C2到G1,每个消费者只会从其中2个分区读取消息。例如C1读取分区0和2,C2读取分区1和3,如下图所示:

如果G1有4个消费者,那么每个消费者只会从其中1个分区读取消息。如下图所示:

如果消费者的数量比分区的数量要多,多出的消费者会处于空闲状态而不会从任何分区读取消息。如下图所示:

Kafka的消费者通常会执行一些高延时的操作,例如是写数据到数据库、对数据进行耗时的计算。在这种情况下,单个消费者不可能及时读取新的消息,因此添加消费者是提高读取消息性能的主要方法。注意,正如上述所说的,消费者的数量不能超过分区的数量,否则会造成资源浪费,因为多出的消费者会处于空闲状态。另外,多个应用从同一个topic读取消息的情况也是非常普遍的。事实上,这也是Kafka的主要设计目标之一。与许多传统的消息系统不同,Kafka在不降低性能的情况下仍然能够支持大量的消费者和消费者组。

例如下图所示,添加一个有2个消费者的消费者组G2,那么G2也会和G1一样读取T1的所有消息。

1.2 消费者组和分区再均衡

当分区的所有权从一个消费者变为另外一个消费者称为分区再均衡。当向消费者组添加一个新的消费者时,它将从之前由另外一个消费者消费的分区中读取消息。当一个消费者被停止或者发生故障时,它会被该消费者组移除,原来由它读取消息的分区会被剩余的其中一个消费者消费。当消费者组消费的topic被修改时(例如,管理员添加新的分区),分区再均衡也会被触发。

分区再均衡是非常重要的,因为它为消费者组提供了高可用性和可扩展性(允许我们容易地和安全地添加和移除消费者),但通常它是不希望发生的。在分区再均衡期间,所有消费者会暂停读取消息,因此分区再均衡基本上会造成整个消费者组的短暂停止。另外,当分区被重新分配给另外一个消费者时,该消费者会丢失其当前的状态;如果它正在缓存任何数据,它将需要刷新它的缓存,这会减缓消息的读取性能直到该消费者重新设置它的状态。

消费者维持分配给它们的分区的所有权是通过向作为该组协调器的Kafka broker发送心跳(不同消费者组的协调器可以是不同的broker)。只要消费者定期发送心跳,它就会被认为是正常的。如果一个消费者停止发送心跳超过一定的时间,其session会超时,该组的协调器会认为它故障并触发分区再均衡。当正常停止一个消费者时,该消费者将通知组协调器它正在离开,组协调器将立即触发分区再均衡。

2. 创建消费者

从Kafka读取消息的第一步是创建一个消费者,类似于创建生产者,也必须指定三个属性:bootstrap.servers、key.deserializer和value.deserializer,第一个之前介绍生产者的时候有详细说明,这里不再重复,简单来说就是用于与Kafka集群建立初始连接的主机和端口的列表。第二个和第三个对应生产者的key.serializer和value.serializer,指定用于把byte数组反序列化为Java对象的类名。

另外还有一个属性group.id,但不是严格强制的,它用于指定该消费者所属的消费者组。

下面是创建消费者的代码示例:

import java.util.Properties;
import org.apache.kafka.clients.consumer.KafkaConsumer;

Properties props = new Properties();
props.put("bootstrap.servers", "broker1:9092,broker2:9092");
props.put("group.id", "CountryCounter");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);

3. 订阅消息

Kafka允许消费者订阅一个或多个topics的消息,只需要调用subscribe()方法,该方法接收一个需要订阅的topic列表:

import java.util.Collections;

consumer.subscribe(Collections.singletonList("customerCountries"));

也可以使用正则表达式匹配多个topic的名字,下面是匹配前缀为test.的topics:

import java.util.regex.Pattern;

consumer.subscribe(Pattern.compile("test.*"));

注意,在创建一个新的topic时,如果消费者订阅的topic正则表达式匹配新的topic,那么分区再均衡会被立即触发,该消费者会开始从新的topic读取消息。

4. Poll循环

消费者API的核心部分是用一个简单的循环不断地轮询服务器读取新的消息。一旦消费者向topics订阅消息,这个poll循环将会处理协调器的所有操作,例如,分区再均衡、读取消息等。从而为开发人员提供了一个简单地从分配的分区读取数据的API。以下是其主要的实现代码:

try {
    while (true) {
        ConsumerRecords<String, String> records = consumer.poll(100);
        for (ConsumerRecord<String, String> record : records) {
            log.debug("topic = %s, partition = %s, offset = %d, custo
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值