4.0 新消费者

上一章分析了Scala实现的两种消费者API,新版本的消费者采用Java重新实现。但不管采用什么版本实现,消费者消费消息的主要工作没有太大变化,比如为消费者分配分区、拉取线程拉取消息、客户端消费消息、更新拉取状态、提交偏移量。消息消费相关的基本概念在第3章中已经分析过了,本章首先会比较下面3个概念:消费者API(下文简称“新API”)、旧版本的高级API(下文简称“高级PI”)和新版本的生产者API。

  1. 消费者的高级API和新API
    先来复习下旧消费者的高级API示例。客户端创建消费者连接器和消息流列表,每个消息流对应一个消费者选代器,最后循环使用消费者迭代器读取每条消息。相关代码如下:
    在这里插入图片描述

下面是新消费者客户端的示例。配置信息指定要连接的Kafka集群,然后创建消费者实例(KafkaConsumer),消费者会订阅主题,最后使用一个循环不断地轮询消费消息:

final Properties consumerProperties = new Properties();
        consumerProperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka);
        consumerProperties.put(ConsumerConfig.GROUP_ID_CONFIG, "broker-compatibility-consumer");
        consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
        consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        if (eosEnabled) {
            consumerProperties.put(ConsumerConfig.ISOLATION_LEVEL_CONFIG, IsolationLevel.READ_COMMITTED.name().toLowerCase(Locale.ROOT));
        }

        final KafkaConsumer<String, String> consumer = new KafkaConsumer<>(consumerProperties);
        consumer.subscribe(Collections.singletonList(SINK_TOPIC));

        while (true) {
            final ConsumerRecords<String, String> records = consumer.poll(100);
            for (final ConsumerRecord<String, String> record : records) {
                if (record.key().equals("key") && record.value().equals("value")) {
                    consumer.close();
                    return;
                }
            }
        }

客户端使用新API,主要调用了KafkaConsumer类提供的两个方法:订阅和轮询。

  • subscribe(Topic)。该方法使用消费组的管理功能,再平衡时“动态分配”分区给消费者(类似于高级API)。还有一个assign(Partition)方法会“静态分配”指定分区给消费者,没有消费组的自动负载均衡和再平衡操作(类似于低级API)。
  • poll()。该方法轮询返回消息集,由于调用一次轮询只得到一批消息,因此需要使用外部的死循环来不断读取消息(类似于高级API消息流对应的迭代器,但没有外部的死循环)。

表4-1比较了高级API和新API在客户端使用方式上的几个不同点。比如分配分区时,高级API通过ZK监听器触发,新API会发送请求给协调者去处理。提交偏移盘时,高级API可以写到ZK或者协调者,新API会写到协调者。消费消息时,高级API通过迭代器进行,新API会循环轮询方法返回的记录集。
在这里插入图片描述

如图4-1所示,高级API的消费者连接器会使用一个后台线程,定时地提交偏移盘到ZK或者协调者节点上。新API提交偏移量除了有一个向动提交偏移量的后台任务,还提供了同步和异步两种模式的偏移量提交方法。新API不仅在偏移量上保持了统一,订阅消息的方式也定义了subscribe()和assign()两个方法,分别对应高级API使用消费者连接器订阅主题和低级API使用SimpleConsumer手动指定分区。消费者客户端不需要使用不同的对象,使用起来更简单。
在这里插入图片描述

  1. 新API的生产者和消费者客户端

对比一下采用新版本构造的生产者和消费者客户端,两者的共同点是都有元数据(Metadata)和
网络客户端(NetworkClient)。不同点是生产者有记录收集器(RecordAccufllulator)、发送线程(Sender)、分区器(Partitioner),消费者有订阅状态(SubscriptionState)、拉取钱程(Fetcher)、分区分配(PartitionAssignor)、消费者的协调者(ConsufllerCoordinator)。相关代码如下:

在这里插入图片描述

如图4-2所示,生产者和消费者对于服务端而言都属于客户端,使用Java开发的新版本客户端把网络层抽象了出来,生产者和消费者的网络层实际上用的是同一套通信机制,即都采用了基于选择器模式的网络客户端。网络客户端会分别用于生产者的发送线程和消费者的拉取线程。生产者在创建KafkaProducer时就立即启动发送线程,而消费者创建KafkaConsufller时并不会立即启动拉取线程,因为拉取线程需要有分区才可以正常运行。生产者发送生产请求和消费者发送拉取请求,最后都会通过网络客户端的选择器轮询将客户端请求发送给服务端。

生产者和消费者客户端还都需要在本地保存服务端集群的元数据(元数据保存了集群的节点列表、主题和分区的关系、节点和分区列表等信息),否则在需要这些信息时就只能通过向服务端发送相关的请求来完成。
在这里插入图片描述
注意:客户端的NetworkCHent管理了客户端与多个服务端节点的网络连接,但新创建的NetworkCUent并没有直接连接服务端节点,因为这时候客户端还没有开始工作,并不知道具体妥连接哪些服务揣。只有在确定了目标节点后,NetworkClient才和需要的服务端节点进行通信。

  1. 消费者高级API和新API的组件

如图4-3所示,高级API和新API分别使用不同的组件拉取消息。粗线部分表示和客户端应用程序直接交互的对象。两种API有一些组件类似,比如消费者连接器类似KafkaConsu~町,ZK监昕器类似消费者的协调者(ConsufllerCoordinator),消费者迭代器类似消费者记录集(ConsufllerRecords)
在这里插入图片描述
消费者更新分区的状态有两种:拉取状态和消费状态。高级API使用分区信息对象(PartitionTopicinfo)记录这两种状态,由于更新拉取状态的拉取线程和更新消费状态的消费者迭代器在不同作用域内,需要将分区信息对象相继传给消费者拉取管理器、消费者拉取线程、消费者迭代器。新API使用SubscriptionState保存订阅状态,也记录了分区的拉取状态和消费状态。新创建的订阅状态会传给消费者的协调者对象和拉取线程。

相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页