Kafka技术内幕 读书笔记之(三) 消费者:高级API和低级API——消费者启动和初始化

消费者启动和初始化
 
 消费者的配置信息要指定连接的ZK集群以及消费组编号 消费者客户端会通过消费者连接器( ConsumerConnector)连接ZK集群,获取分配的分区, 
建每个主题对应的消息流( KafkaStream ),最后迭代消息流,读取每条消息,并完成具体的业务处理逻辑


消费者客户端通过消费者连接器读取消息的具体步骤如下
(1)  消费者的配置信息指定订阅的主题和主题对应的线程数, 每个线程对应一个消息流
(2)  Consumer对象通过配置文件创建基于ZK的消费者连接器
(3)消费者连接器根据主题和线程数创建多个消息流
(4)在每个消息流通过循环消费者迭代器( ConsumerIterator)读出消息

  一个消费者进程允许为不同的主题设置不同的消费者线程数量 比如,我们可以为重要的主题设置更多的线程数以加快消费进度,不同主题之间互相隔离,不会互相影响 
 而且即使是相同的主题,不同的线程之间也不像Java的多线程那样需要加锁等重量级的同步方案 因为消费者采用多线程访问的分区都是隔离的,所以不会出现相同一个分区
被不同线程同时访问的情况 前面我们说过“一个分区只会被分配给消费组中的一个消费者”,实际上从线程模型来看,更准确地讲应该是“一个分区只会被分配给一个消费者线程”
  消费者连接器不仅要处理分区分配和拉取消息这些和消费逻辑相关的任务,而且要在线程模型方面保证不同线程的处理逻辑都一致
如图 (左)所示-个消费者进程订阅的主题设置了 3个线程。而图 (右)有3个消费者进程,但每个消费者订阅的主题只有一个线程。 这两种方式的效果应该 
是一样的:都能够消费所有的分区,只不过对于外部ZK而言,一个消费者和3个消费者在消费组看来 消费组成员列表是不同的 。 

创建并初始化消费者连接器
  消费者只需要消费者配置( ConsuMerConfig )就可以创建消费者连接器 消费者连接器接口的主要方法有:createMessageStreams ()方法,它创建消息流并返回给客户端应用程序, 
 这样客户端就会使用消息流读取消息 ; commitOffsets ()方法,它会提交分区的偏移量元数据到ZK或者Kafka的内部主题中 
  除了上面暴露给客户端使用的两个方法,消费者连接器还会协调下面的各个组件来读取消息

listeners。 注册主题分区的更新、会话超时、消费者成员变件,触发再平衡
zkUtils 。 从ZK中获取主题、分区、消费者列表,为再平衡时的分区分配提供决策
topicRegistry。消费者分配的分区,结构是“主题→(分区→分区信息)”
fetcher。消费者拉取线程的管理类,拉取线程会向服务端拉取分区的消息
topicThreadldAndQueues 。 消费者订阅的主题和线程数,每个线程对应个队列
offsetsChannel 。偏移量存储为Kafka 内部主题时,需要和管理消费组的协调者通信

下图展示了消费者连接器中这些组件如何协调完成消息的消费 其中,监听器(1)是消息消费事件的导火索, 旦触发了再平衡,
需要从ZK中读取所有的分区和已注册的消费者(2) 然后通过分区分配算法,每个消费者都会分配到不同的分区列表(3) 
 接着拉取线程开始拉取对应的分区消息(4),并将拉取到的消息放到每个线程的队列中(5),最后消费者客户端就可以从队列中读取什i消息了 
 另外,为了及时保存消费进度,我们还需要将偏移量’保存至UoffsetsChannel.lfil道对应的节点中(6)

为了保证再平衡时各项准备工作都已就绪,创建消费者连接器时,需要执行以下初胎化方法
(1)保连接上 ZK , 因为消费者要和 ZK通信,包括保存消费进度或者读取分区信息等
(2)创建管理所有消费者拉取线程的消费者拉取管理器( ConsumerFetcherManager
(3)确保连接上偏移量管理器( OffsetManager),消费者保存消费进度到内部主题时和它通信
(4)调度定时提交偏移量到ZK或者Kafka 内部主题的线程

消费者客户端的线程模型
  消费者连接器为了存储拉取线程拉取的消息,本质上还是使用“队列”这种具有缓冲功能的数据结构 。 将队列封装到消息流中,
队列和消息流是一一对应的
  消费者客户端线程模型的主要概念有消费者线程、队列、消息流, 者的关系都是一一对应的 。如果将线程模型和服务端的分区再结合起来,
 个线程允许分配多个分区,那么多个分区会共用同个线程对应的个队列和个消息流
  消费者客户端只需要指主订阅的主题和线程数量,具体主题分成几个分区、线程分配到了哪些分区、分区分布在哪些节点上,对客户端都是透明的
 客户端的关注点是每个线程都对应一个队列,每个队列都对应了一个消息流,只要队列中有数据,就能从消息流中迭代读取出消息
队列作为消息流和拉取线程的共享内存数据结构,会通过消费者连接器的 topicThreadldAndQueues全局引用,传递到拉取线程
当拉取线程往队列中填充数据时,消费者客户端就可以通过消息流从队列读取消息

重新初始化消费者
  消费者连接器在注册消费者至ZK后,会执行重新初始化消费者启动时希望被加入消费组,必须执行次初始化方法,并触发消费组内所有消费者成
员(当然也包括自己)的再平衡
如下图 所示,触发消费者连接器执行再平衡操作有两种方式:外部事件和直接触发 直接触发会在消费者启动时执行,即重新初始化消费者时,强制触发次再平
外部事件会通过下面3种监听器和线程检查的方式触发再平衡
当新的会话建立或者会话超时需要重新注册消费者,并发再平衡
当主题的分区数量变化时,触发再平衡
当消费组成员变化时,触发再平衡

每个消费者在启动时都要订阅3种事件:会话超时事件、消费组的子节点变化事件(消费者增减)主题的数据变化事件(分区增减)这3种事件任何一个发生,
都会触发再平衡操作 。 

原文地址:https://www.cnblogs.com/jixp/p/9818035.html