3.2.2 为消费者分配分区


3.2.2 为消费者分配分区

每一个消费者都需要分配到分区才能拉取信息,当发生再平衡时,消费组中的所有消费者都会重新分配分区。 为了让每个消费者都能被分配到分区,需要从ZK中查询出所有的分区以及所有的消费者成员歹lj表 。 当然,分区要限定主题范围,消费者要限定消费组范围 。 对于触发再平衡的消费者而言,它所属的消费组是确定的,而且订阅的主题和分区也是确定的,所以从ZK中获取订阅相同主题的消费者成员列表、包含相同主题的分区都没有问题。

如图3-13所示,消费者l订阅了主题1和主题2,消费者2订阅了主题1和主题3,消费者3订阅了主题2和主题3。当消费者l发生再平衡时,因为消费者1订阅了主题l和主题2,而主题l和主题2的订阅者有消费者1、消费者2、消费者3,所以消费者2和消费者3也会一起发生再平衡。

在这里插入图片描述
这个示例中我们并没有说明消费者1发生再平衡操作的原因,有可能是消费者1的会话超时,或者消费者l刚加入消费组,或者消费者l订阅的主题(主题l和主题2)分区发生变化。也有可能是其他消费者发生再平衡,导致消费者l也需要执行再平衡。

每个消费者再平衡时,都会创建一个代表分区分配的上下文对象(AssignmentContext)。上下文对象最主要的是要提供两个变量一一一所有的分区(partitionsForTopic)、所有的消费者线程(consumersForTopic),这样分区分配算法才可以工作。相关代码如下:
在这里插入图片描述
分区分配上下文对象的变量会被PartitionAssignor执行分区分配时用到。PartitionAssignorassign()方法将所有的分区分配给所有消费者的算法为:将分区数除以线程数,表示每个消费者线程平均可以分到几个分区。如果除不尽,剩余的会依次分给前面几个消费者线程。相关代码如下:
在这里插入图片描述
如图3-14所示,有2个消费者,每个消费者都有2个线程,一共有5个可用的分区。每个消费者线程(一共4个线程)都可以获取至少l个分区(5/4=1),剩余l个(5%4=1)分区分给第一个线程。最后分区分配给各个消费者的结果为:PO→Cl_O,Pl→Cl_O,P2→Cl_1,P3→C2_0,P3→C2_1。

在这里插入图片描述
PartitionAssignor分配分区的算法针对的是消费组的所有消费者。assign()方法的返回值表示所有消费者(而不是当前消费者)的分区分配结果。当前消费者在ZKRebalancelistener·rebalance()方法中调用assign()方法后,还需要根据消费者编号,从全局的分配结果中查询出属于向己的分配分区。

再平衡操作的基本条件是为当前消费者分配到分区,这样拉取线程才能知道要从哪里拉取消息。另外,分区的消费进度保存在ZK中,所以也要读取ZK获取最新的偏移量。只有把这些工作都准备好,拉取线程才可以开始工作。相关代码如下:
在这里插入图片描述
rebalance()方法除了前面已经分析的所有权释放和添加、拉取钱程的关闭和更新,剩下和l分区分配相关的步骤如下。

(1)构造消费者的分配上下文,得到订阅主题的分区和所有的消费者线程信息。
(2)分区分配算法计算每个消费者的分区和消费者线程的映射关系。
(3)从步骤(2)的全局结果中获取属于当前消费者的分区和消费者线程。
(4)读取当前消费者拥有的分区在ZK中的最新消费进度,即它所拥有分区的偏移量。
(5)构造PartitionToptcinfo,加入到表示消费者的主题注册信息的topicRegistry中。
(6)更新topicRegistry,后面的拉取线程会使用该数据结构。
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页