文章摘要(AI生成)
Kafka在消息发送和消费过程中通过实现不同的分区策略来确保消息均匀地分发到不同的topic和partition上,以及消费者均匀地消费不同的partition。生产者的分区策略包括默认分区策略、轮询式分区策略和粘性分区策略,消费者的分区策略包括范围分配策略、轮询分配策略和粘性分配策略。当topic/partition数量或消费者数量变化时,会触发重平衡(rebalance)操作,通过加入组和组信息同步来重新分配消费者要消费的分区,确保各分区能够重新分配到消费者进行消费。整体而言,Kafka通过不同的分区策略和重平衡操作来保证消息生产和消费的高并发性和均衡性。
日常使用kafka时,在发送消息和消费消息的时候经常会有两个困惑:
- kafka如何把我们发送者的消息均匀的分发到不同的topic和partition上的?
- 在消费时,又是怎么将这些partition中的消息均匀的分发到我们不同的消费者上的?
为了解决这两个问题,kafka在生产和消费时通过实现了各种不同的分区策略来保证partition在接受消息和分发消息时的高并发性。示意如下:
生产者分区策略
实际使用时配置方式
生产者消费策略有手动指定partition和指定key两种方式。代码实现上来看,指定partition的优先级高于指定key。
以我们调用kafkaTemplate进行消息发送为例,进行源码走读:
- 通过spring kafka组件中的kafkatemplate进行消息发送
- kafkatemplate的send方法的底层则是对kafka api的封装,直接调用的kafkaProducer.doSend方法进行实现的
- 而doSend方法partition获取是通过如下方法获取的:
通过源码可以看到获取方式为:如果ProducerRecord中传的partition为空时,才会取partitioner中的分区方法计算应发到哪个分区。
partitioner中的分区方法我们可以自己继承Partitioner接口实现,我们需要在生产者的配置中指定我们的分区实现类:
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, DefaultPartitioner.class)
kafka也提供了三种发送分区策略:DefaultPartitioner
、RoundRobinPartitioner
、UniformStickyPartitioner
,可以直接在配置的时候指定相关策略实现类
三种分区策略解读
DefaultPartitioner
-默认分区策略
- 如果未指定分区但存在key,则根据我们配置的key序列化器进行序列化后的key使用murmur2哈希算法对分区数进行取模
- 如果不存在key和分区,则会使用粘性分区策略
UniformStickyPartitioner
-纯粹的粘性分区策略
- 不管是否存在key,都统一用粘性分区策略分配
RoundRobinPartitioner
-分区策略
- 使用轮询机制,将消息平均分配到每个分区中
消费者分区策略
消费分区策略解决的是为消费者组中的各消费者分配要消费的partition,例如在有10个分区5个消费者的情况就需要根据消费分区策略指定消费者对应的分区。这种分配策略的触发时机就是在分区数量和消费者数量变化的时候,所以又叫重平衡策略
使用时配置方式
消费分区策略在开发中的配置项为ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG
,实际应用中可选用RangeAssignor
(默认),RoundRobinAssignor
与StickyAssignor
三种分区策略解读
RoundRobinAssignor
-分配策略
将所有的分区按顺序进行排序,轮询式地分配给每一个消费者
该策略保证了如果同一个消费者组内所有消费者订阅的主题都是相同的,那么策略的分区分配也是均匀的。
RangeAssignor
-分配策略
将单个topic中的主题按顺序排序,然后将他们划分为固定大小的分区段,每一个分区段分配给同一个消费者
这种分配方式明显的一个问题是随着消费者订阅的Topic的数量的增加,不均衡的问题会越来越严重
StickyAssignor
-粘性策略
每一次分配变更相对上一次分配做最少的变动。其目标有两点:
- 分区的分配尽量的均衡。
- 每一次重分配的结果尽量与上一次分配结果保持一致。
当这两个目标发生冲突时,优先保证第一个目标。第一个目标是每个分配算法都尽量尝试去完成的,而第二个目标才真正体现出StickyAssignor特性的。
三种策略总结
RangeAssignor与RoundRobinAssignor在节点变更时,会遍历所有分区和消费者组,按范围划分/轮询对全部分区再次进行重新分配消费者,特点:牵一发动全身
StickyAssignor在节点变更时,让目前的分配尽可能保持不变,只挪动尽可能少的分区来实现重平衡,特点:微操大师
消费者分区策略与reblance?
reblance发生的原因:topic/partition数量或者消费者数量发生变更时,由于需要通过消费分区策略重新分配消费者要消费的分区,所以需要所有消费者停止消费等待分区重新分配完成。
reblance主要分为两个操作,加入组(join group)和组信息同步(sync group)。
-
加入组(join group)
这一步主要是该Group的所有成员向其
Group Coordinator
发送JoinGroup
请求,请求加入消费者组。一旦所有成员都发送了JoinGroup
请求,Coordinator
就会从所有消费者组成员中选取一个作为leader,并把组成员信息和订阅信息也发给leader。 -
组信息同步(sync group)
这一步主要是leader分配消费方案。完成分配后,会把分配方案(即根据分区策略算好的消费分区方案)封装
syncGroup
请求中发送给Coordinator
,其中非leader也会发送syncGroup
请求给Coordinator
,只是请求信息为空,Coordinator
接收到syncGroup
请求中的分配方案后,会把方案作为syncGroup
的响应信息发送给各个成员。这样每个组成员都知道自己该消费那些分区了。
最终在topic/partition数或消费者数变更后,使得所有分区能够再次重新分配到消费者进行消费
评论区