Kafka的分区策略

在kafka中,每个topic一般会有很多个Partitions。为了使我们能够及时的消费消息!  我们也可能启动多个Consumer去消费分区,而每个Consumer同样会启动一个或者是多个streams去分别消费Topic里面的数据。我们又知道,在Kafka中存在着Consumer Group的概念,也就是在group.id 一样的Consumer,这些Consumer属于同一个Consumer Group,在组内所有消费者协调在一起来消费订阅主题(subscribed topics)的所有分区(partition),当然消费者在消费的时候也是有规则限定的,这个规则就是:每个分区只能被同一个消费组内的一个consumer来消费。也就是!同一个消费组里面的consumer一次不能够去消费同一个Topic的Partition。  那么问题来了,同一个Consumer Group里面的Consumer是如何知道该去消费哪些分区里面的数据呢!?

    

    就像上面图示, Consumer 1 为什么消费的是Partition0 和Partition2呢??而不是消费的Partition0和Partition3呢?或者是其他呢!?这就涉及到Kafka内部分配策略(Partition Assignment Strategy)!

    说到Kafka分区分配策略,就是它的内部的默认的分区分配策略:Range 和 RoundRobin(轮询)。当下面的事情发生的时候,Kafka将会进行一次分区分配。

        1、当同一个Consumer Group 内新增消费者。(消费者层面发生改动)

        2、消费者离开当前所属的Consumer Group,包括Shuts down(关闭、停工)或者是crashes(崩溃)。(消费者层面发生改动)

        3、就是消费者订阅的主题新增的分区的时候!

将分区的所有权从一个消费者移到另一个消费者成为重新平衡(rebalance),如何rebalance就涉及到分区分配策略。

我们假设有一个名为Top1的主题,它有十个分区,然后我们有两个消费者(C1、C2)来消费这十个分区里面的数据,而且C1的num.streams=1,C2的num.streams=2。

下面介绍第一个默认的分区策略:Range  Startegy(根据范围消费)

    Range startegy是对每个主题而言的 , 首先对同一个主题里面的分区按照序号进行排序,并对消费者按照字母进行排序。在对十个分区排序的话是0-9;消费者线程排完序是C1-0,C2-0,C2-1。然后用partitions的总数除以消费者的总数来决定每个消费者线程消费几个分区。如果有余数,那么前面的几个消费者线程将会多消费一个分区。在我们的例子里面,我们有十个分区,三个消费者线程,10/3=3---1,那么消费者线程C1-0    将会多消费一个分区,所以最后分区分配的结构看起来是这样的:

    C1-0将消费0,1,2,3分区

    C2-0将消费4,5,6分区

    C2-1将消费7,8,9分区

如果有第十一个分区的话,那么分区是这样的

    C1-0将消费0,1,2,3分区
    C2-0将消费4,5,6,7分区

    C2-1将消费8,9,10分区

如果我们有2个主题(T1和T2),分别都有十个分区,那么最后的分配结果是:

     C1-0将消费T1主题中的0,1,2,3分区以及T2主题中0,1,2,3分区

     C2-0将消费T1主题中的4,5,6分区以及T2主题中的4,5,6,分区

     C2-1将消费T1主题中的7,8,9分区以及T2主题中的7,8,9分区

这就是消费的策略! 就是用总的分区数/消费者线程总数=每个消费者线程应该消费的分区数。当还有余数的时候就将余数分别分发到另外的消费组线程中。  

在这里我们不难看出来。C1-0消费者线程比其他消费者线程多消费了两个分区,这就是Range Strategy的一个明显的弊端。 当分区很多的时候,会有个别的线程压力巨大!

 

下面介绍的是第二个默认的分区策略:RoundRobin strategy(轮询的消费策略)

在使用RoundRobin Starategy的时候我们必须满足两个条件:

    1、同一个consumer Group里面的所有消费者的num.streams必须相等;

    2、每个消费者订阅的 主题必须相同

在这里我们假设2个消费者的num.streams=2.  RoundRobin starategy的工作原理: 将所有主题的分区组成TopicAndPartition列表,然后对TopAndPartition列表按照hashcode进行排序,下面是代码!

 

最后按照round-robin风格将分区分别分配给不同的消费者线程。

在我们的例子中,假如按照hashcode排序完的topic-partition组依次为T1-5,T1-3,T1-0.T1-8.T1-2,T1-1,T1-4,T1-6,T1-9,我们的消费者线程排序为C1-0, C1-1 ,C2-0,C2-1,最后分区分配结果为:

    C1-0将消费T1-5 , T1-2 , T1-6 分区;

    C1-1将消费T1-3 , T1-1 , T1-9 分区;
    C2-0将消费T1-0 , T1-4分区;

    C2-1将消费T1-8 , T1-7分区;

遗憾的是,目前我们还不能自定义分区分配策略,只能通过partition.assignment.strategy参数选择range或roundrobin。  partition.assignment.strategy参数默认的值是range。

你可能感兴趣的:(Kafka)