kafka 主动消费_Kafka 消费者 Java 实现

应用程序使用 KafkaConsumer向 Kafka 订阅 Topic 接收消息,首先理解 Kafka 中消费者(consumer)和消费者组(consumer group)的概念和特性。

KafkaConsumer

消费者和消费者组

当生产者向 Topic 写入消息的速度超过了消费者(consumer)的处理速度,导致大量的消息在 Kafka 中淤积,此时需要对消费者进行横向伸缩,用多个消费者从同一个主题读取消息,对消息进行分流。

Kafka 的消费者都属于消费者组(consumer group)。一个组中的 consumer 订阅同样的 topic,每个 consumer 接收 topic 一些分区(partition)中的消息。同一个分区不能被一个组中的多个 consumer 消费。

假设现在有一个 Topic 有4个分区,有一个消费者组订阅了这个 Topic,随着组中的消费者数量从1个增加到5个时,Topic 中分区被读取的情况:

Kafka consumers

如果组中 consumer 的数量超过分区数,多出的 consumer 会被闲置。因此,如果想提高消费者的并行处理能力,需要设置足够多的 partition 数量。

除了通过增加 consumer 来横向伸缩单个应用程序外,还会出现多个应用程序从同一个 Topic 读取数据的情况。这也是 Kafka 设计的主要目标之一:让 Topic 中的数据能够满足各种应用场景的需求。

如果要每个应用程序都可以获取到所有的消息,而不只是其中的一部分,只要保证每个应用程序有自己的 consumer group,就可以获取到 Topic 所有的消息:

Kafka consumer groups

横向伸缩 Kafka 消费者和消费者群组并不会对性能造成负面影响。

分区再均衡

一个消费者组内的 consumer 共同读取 Topic 的分区。

当一个 consumer 加入组时,读取的是原本由其他 consumer 读取的分区。

当一个 consumer 离开组时(被关闭或发生崩溃),原本由它读取的分区将由组里的其他 consumer 来读取。

当 Topic 发生变化时,比如添加了新的分区,会发生分区重分配。

分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为再均衡(rebalance)。再均衡非常重要,为消费者组带来了高可用性和伸缩性,可以放心的增加或移除消费者。

再均衡期间,消费者无法读取消息,造成整个 consumer group 一小段时间的不可用。另外,当分区被重新分配给另一个消费者时,当前的读取状态会丢失。

消费者通过向作为组协调器(GroupCoordinator)的 broker(不同的组可以有不同的协调器)发送心跳来维持和群组以及分区的关系。心跳表明消费者在读取分区里的消息。消费者会在轮询消息或提交偏移量(offset)时发送心跳。如果消费者停止发送心跳的时间足够长,会话就会过期,组协调器认为消费者已经死亡,会触发一次再均衡。

在 Kafka 0.10.1 的版本中,对心跳行为进行了修改,由一个独立的线程负责心跳。

消费 Kafka

创建 Kafka 消费者

在读取消息之前,需要先创建一个 KafkaConsumer 对象。创建 KafkaConsumer 对象与创建 KafkaProducer 非常相似,创建 KafkaConsumer 示例:

Properties props = new Properties();

props.put("bootstrap.servers", "broker1:9092, broker2:9092");

// group.id,指定了消费者所属群组

props.put("group.id", "CountryCounter");

props.put("key.deserializer", "org.apache.kafka.common.serializaiton.StrignDeserializer");

props.put("value.deserializer", "org.apache.kafka.common.serializaiton.StrignDeserializer");

KafkaConsumer consumer =

new KafkaConsumer(props);

订阅主题

创建了消费者之后,需要订阅 Topic,subscribe() 方法接受一个主题列表作为参数:

// topic name is “customerCountries”

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

subscribe() 也可以接收一个正则表达式,匹配多个主题(如果有新的名称匹配的主题创建,会立即触发一次再均衡,消费者就可以读取新添加的主题)。在 Kafka 和其他系统之间复制数据时,使用正则表达式的方式订阅多个主题是很常见的做法。

// 订阅所有 test 前缀的 Topic:

consumer.subscribe("test.*");

消息轮询

消息轮询是消费者的核心,通过轮询向服务器请求数据。消息轮询 API 会处理所有的细节,包括群组协调、分区再均衡、发送心跳和获取数据,开发者只需要处理从分区返回的数据。消费者代码的主要部分如下所示:

try {

while (true) {

// 100 是超时时间(ms),在该时间内 poll 会等待服务器返回数据

ConsumerReccords records = consumer.poll(100);

// poll 返回一个记录列表。

// 每条记录都包含了记录所属主题的信息、记录所在分区的信息、记录在分区里的偏移量,以及记录的键值对。

for (ConsumerReccord record : records) {

log.debug("topic=%s, partition=%s, offset=%d, customer=%s, country=%s",

record.topic(), record.partition(), record.offset(),

record.key(), record.value());

int updatedCount = 1;

if (custCountryMap.countainsValue(record.value())) {

updatedCount = custCountryMap.get(record.value() ) + 1;

custCountryMap.put(record.value(), updatedCount);

JSONObject json = new JSONObject(custCountryMap);

System.out.println(json.toString());

}

}

} finally {

// 关闭消费者,网络连接和 socket 也会随之关闭,并立即触发一次再均衡

consumer.close();

}

在第一次调用新消费者的 poll() 方法时,会负责查找 GroupCoordinator,然后加入群组,接受分配的分区。如果发生了再均衡,整个过程也是在轮询期间进行的。心跳也是从轮询里发送出去的。

消费者配置

Kafka 与消费者相关的配置大部分参数都有合理的默认值,一般不需要修改,不过有一些参数与消费者的性能和可用性有很大关系。接下来介绍这些重要的属

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值