Kafka 消费者及消费者分区策略

消费方式:

consumer 采用 pull(拉)模式从 broker 中读取数据。

  push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的

它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而 pull 模式则可以根据 consumer 的消费能力以适 当的速率消费消息。

  pull 模式不足之处是,如果 kafka 没有数据,消费者可能会陷入循环中,一直返回空数 据。针对这一点,Kafka 的消费者在消费数据时会传入一个时长参数 timeout,如果当前没有 数据可供消费,consumer 会等待一段时间之后再返回,这段时长即为 timeout。

一个 consumer group 中有多个 consumer,一个 topic 有多个 partition,所以必然会涉及 到 partition 的分配问题,即确定那个 partition 由哪个 consumer 来消费。

Kafka 有三种分配策略,

RoundRobinAssignor分配策略
RangeAssignor(默认)
StickyAssignor分配策略
 
一、 RoundRobinAssignor:

第一种例子 所有分区是一个主题

 0-6一共7个分区,轮询给消费者组种的消费者消费。

第二个例子 消费者消费多个主题

   

  例如T1三个分区,T2主题也有3个分区,我们的消费者组里有2个消费者。2个消费者都订阅了主题T1T2, RoundRobin中 会把两个主题中当作一个整体, 将分区对象(TopicAndPartition)的hash值排个序,分别给2个消费者。

  但是这种策略存在问题:

  

  如果,同一个消费者组中的A、B两个消费者,A订阅T1、T2; B订阅T2、T3,那么会把T1T2T3当作一个整体,就会导致B未订阅T1也会收到T1的分区;或者同一个消费者组 A订阅T1,B订阅T2,也有可能导致A消费T2....会有问题。所以kafka中默认的消费分区策略是range策略。

 
二、RangeAssignor:先看订阅的消费者,再看组。

  7/3 = 2;第一个给三个,后面每个给两个。 

   存在的问题:可能会导致不均衡。因为range分区策略是按主题来划分。

 例如:一个消费者组中A、B两个消费者,订阅了主题T1和T2. range是按主题来分别分区的。那么A消费T1的0,1分区,消费T2的0 1分区,随着主题增多,这里消费者之间消费的分区数将不均衡。

再来看一个例子:

  

A、B消费者属于同一个消费者组,C是另一个消费者组。A、B订阅了T1主题,B订阅了T2主题。C订阅了T1主题:

如果是RoundRobin 分区策略,把T1、T2的6个对象作为一个整体,往AB分组发,可能导致A收到T2主题的数据;

所以要用range分区策略:range分区要按主题划分,C单独消费T1; T1的0、1分区给A  , 2分区给B;

对于T2主题,按主题划分需要先看是谁订阅了这个主题,然后才考虑组。

消费者分区策略触发执行时机:

  当消费者数量变化时:例如启动消费者时,或者添加或者减少消费者个数。

当消费者组里的消费者个数发生变化,都要重新分配分区。

三、StickyAssignor分配策略

Kafka从0.11.x版本开始引入这种分配策略,它主要有两个目的:

1、分区的分配要尽可能的均匀;

2、分区的分配尽可能的与上次分配的保持相同。

当两者发生冲突时,第一个目标优先于第二个目标

  假设消费组内有3个消费者:C0、C1和C2,它们都订阅了4个主题:t0、t1、t2、t3,并且每个主题有2个分区,也就是说整个消费组订阅了t0p0、t0p1、t1p0、t1p1、t2p0、t2p1、t3p0、t3p1这8个分区。最终的分配结果如下:

消费者C0:t0p0、t1p1、t3p0
消费者C1:t0p1、t2p0、t3p1
消费者C2:t1p0、t2p1

  这样初看上去似乎与采用RoundRobinAssignor策略所分配的结果相同,但事实是否真的如此呢?再假设此时消费者C1脱离了消费组,那么消费组就会执行再平衡操作,进而消费分区会重新分配。  

  如果采用RoundRobinAssignor策略,那么此时的分配结果如下:

消费者C0:t0p0、t1p0、t2p0、t3p0
消费者C2:t0p1、t1p1、t2p1、t3p1

  如分配结果所示,RoundRobinAssignor策略会按照消费者C0和C2进行重新轮询分配。而如果此时使用的是StickyAssignor策略,那么分配结果为:

消费者C0:t0p0、t1p1、t3p0、t2p0
消费者C2:t1p0、t2p1、t0p1、t3p1

  可以看到分配结果中保留了上一次分配中对于消费者C0和C2的所有分配结果并将原来消费者C1的“负担”分配给了剩余的两个消费者C0和C2,最终C0和C2的分配还保持了均衡

如果发生分区重分配,那么对于同一个分区而言有可能之前的消费者和新指派的消费者不是同一个,对于之前消费者进行到一半的处理还要在新指派的消费者中再次复现一遍,这显然很浪费系统资源。StickyAssignor策略如同其名称中的“sticky”一样,让分配策略具备一定的“粘性”,尽可能地让前后两次分配相同,进而减少系统资源的损耗以及其它异常情况的发生。

原文地址:https://www.cnblogs.com/wsw-seu/p/13443425.html