Kafka-之Consumer客户端与分区分配策略

与KafkaProducer向对应的是KafkaConsumer,用来消费kafka topic中的消息,但是于生产者而言,消费者这里有一个消费者组的概念,在消费的时候通过group.id指定。

整个Consumer的客户端架构图如下:

java消费kafka多个分区 kafka consumer消费多个分区_数据

每个消费者组可以同时消费相同的topic分区数据,但是互不影响,但是一个分区下的数据在同一个消费者组中只能被一个消费者消费;下面就讲讲kafka消费者的分区分配策略。

1 分区分配策略

kafka消费者的分区分配策略通过partition.assignment.strategy或者consumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG来指定。kafka的支持的分区分配策略有3种:

  • RangeAssignor (org.apache.kafka.clients.consumer)
  • RoundRobinAssignor (org.apache.kafka.clients.consumer)
  • StickyAssignor (org.apache.kafka.clients.consumer)

1.1 RangeAssignor

该分区分配策略为默认的策略,是基于不同的topic进行分配的,假如这里有2个topic,每个topic有3个分区,分别表示为

t0p0,t0p1,t0p2

t1p0,t1p1,t1p2

假如此时有2个消费者,c1,c2,首先分别通过分区数量3/消费者数量2=1,且余数为1,那么判定每个消费者至少分配一个分区的数据 ,余下的分区数量分配给第一个分区,这样其实容易造成数据倾斜的现象。

通过该分配策略最终的分配结果为:

c1(t0p0,t0p1,t1p0,t1p1) , c2(t0p2,t1p2)

具体的分配如下:

java消费kafka多个分区 kafka consumer消费多个分区_java消费kafka多个分区_02


java消费kafka多个分区 kafka consumer消费多个分区_apache_03

1.2 RoundRobinAssignor

轮循的分配方式如下分为2种情况:

  • 每个消费者订阅的主题数量是一样的
    假如当前有2个主题t0,t1,每个主题3个分区t0p0,t0p1,t0p2,t1p0,t1p1,t1p2,此时有2个订阅完全一致的consumer c1,c2来消费t0,t1的数据,那么最终的分配结果如下:

c1(t0p0,t0p2,t1p1)

c2(t0p1,t1p0,t1p2)

  • 每个消费者订阅的主题数量是不一样的
    假如当前有3个主题t0,t1,t2每个主题2个分区t0p0,t0p1,t1p0,t1p1,t2p0,t1p1,此时有3个消费者,消费者订阅的c0 subsribe t0,c1 subscribe t0 t1,c2 subscribe t0,t1,t2;相同的topic只会对订阅的消费者进行轮循,此时不同topic的订阅情况如下:

t0 :c0,c1,c2

t1:c1,c2

t2:c2

最终的分配结果如下:

c0(t0p0)

c1(t0p1,t1p1)

c2(t1p0,t2p0,t2p1)

很明显此时的分配是不均衡的。

1.3 StickyAssignor

该分配策略的宗旨有2个:

  • 保证分区分配得尽可能平衡;
  • 在分区需要重新分配时(添加、减少consumer),它尽可能保存原有的分配不动,节省由于partition从一个consumer移动到另一个consumer产生的性能开销。

具体的该策略详情可以参考官网API:StickyAssignor