Kafka-之Consumer客户端与分区分配策略
与KafkaProducer向对应的是KafkaConsumer,用来消费kafka topic中的消息,但是于生产者而言,消费者这里有一个消费者组的概念,在消费的时候通过group.id
指定。
整个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)
具体的分配如下:
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