Kafka分区分配策略

在leader consumer执行partition分配的时候,存在一种特殊的机制,即consumer和partition所在节点机器所在的机架(rack)号相同的时候,会优先分配此partition给这个consumer。下面描述分区分配策略时,也会分启不启用Rack Aware两种情况分别进行分析。

RangeAssignor

partition和consumer排序

partition排序规则

partition按照编号从小到大排序即可。

consumer排序

consumer的排序稍微复杂一些,需要参考group.instance.idmember.id等。

  • 如果双方的group.instance.id都存在,则直接按字典序进行比较
  • 如果只有一方的group.instance.id存在,那么有group.instance.id的排在前面
  • 如果双方都不存在group.instance.id,那么按照各自的member.id基于字典序进行比较

consumer的member.id格式:${client.id}-UUID,默认的client.id的格式为:consumer-${group.id}-${编号}

未启用Rack Aware的分配流程

此流程针对于单个topic的所有partition。

现有如下partition和consumer:

partition: partition 0, partition 1, partition 2

consumer: consumer 0(consumer-test-group-1-UUID), consumer 1(consumer-test-group-2-UUID)

排序结果:

partition 0(编号:0), partition 1(编号:1), partition 2(编号:2)

consumer 0(consumer-test-group-1-UUID), consumer 1(consumer-test-group-2-UUID)

分配结果

总共有3个分区,两个消费者,那么每个消费者平均有 3(分区数) / 2(consumer数) = 1个分区,剩余1个分区(3%2),剩余的分区按照消费者的先后顺序分配,排在前面的优先分配 因此有如下分配结果:

缺点

明显,排在前面的消费者实例会分配到更多的分区,某些情况下并不是很好的方案(比如前面的消费者当前的消费压力已经很大了,某个消息的消费时长过长,导致两次调用poll方法的间隔很长)。

启用Rack Aware的分配流程

启用条件
  • 所有consumer所在的rack和所有topic的partition副本所在的rack没有重叠,这种情况下没有启用Rack Aware的必要
  • 在consumer和partition的rack存在重叠的情况下,preferRackAwareLogic为true时,强制启用Rack Aware,不过此field仅在单测中使用,在正常使用场景下可以直接忽略
  • 在consumer和partition的rack存在重叠的情况下,每个partition的副本所在的rack完全一致,此种情况下无需启用Rack Aware。假设consumer 0 所在的rack为rack-0,既然和partition副本所在的rack有重叠,那么至少存在一个partition 0的某个副本也在rack-0,又因为每个partition的副本所在的rack完全一致,那么其他partition的副本中至少有一个也在rack-0上,即对于consumer 0来说,不管分配哪个分区,这个分区中总有一个副本的rack和consumer 0在一个rack上,也就没有所谓rack一致优先分配的必要了。所以,要启用Rack Aware,至少要有一个分区的副本所在rack和其他分区不一样。

为说明方便,对partition的副本做了简化处理,假设所有partition只有一个leader副本。

现有两个Topic,topic0-1,每个topic都各自有三个partition,partition0-2,以及两个consumer0-1,具体关系以及所在rack如下图所示。

具体流程

由于consumer 0和consumer 1 所在的rack同样存在partition,且两个topic的partition所在的rack不完全相同,因此满足启用Rack Aware机制的前提条件。

RangeAssignorRack Aware机制会将订阅了完全相同的topic的consumer放在一起处理,因此这里,consumer 0 和consumer 1会放在一起进行处理。进一步地,如果这些consumer订阅的topic中有相同数量的partition的,也会放到一起进行处理,因此这里会将topic 0 和topic 1 放到一起进行处理。

接下来,逐个分区开始分配。首先要从consumer中找到第一个其所在的rack和topic 0 和 topic 1 的对应编号的分区所在 rack 都相同 的consumer(实际上只要 consumer 和每个分区对应编号的分区的所有副本所在的rack有一个相同的即可,由于这里做了简化处理,每个分区的副本只有一个,因此需要和这一个副本所在的 rack 一致)。

topic0-1的第一个分区的分配流程:

由于consumer 1 所在的rack: rack 0 和 topic 0 以及 topic 1 的 partition 0 所在的rack是一样的,因此我们会将topic 0 - parititon 0 以及 topic 1 - parititon 0 都分配给 consumer 1。之后判断consumer 1 对于 topic 0 和 topic 1 的分区的分配数量是否已经到了上限。具体上限的计算公式为:

topic 0 总共有3个分区,两个消费者,那么每个消费者平均有 3(分区数) / 2(consumer数) = 1个分区,剩余1个分区(3%2),剩余的分区按照消费者的先后顺序分配,排在前面的优先分配,因此 conusmer 0 最多可以分配到 topic 0 的 2个分区。类似的,consumer 1 最多可以分配到 topic 0 的 1个分区。 topic 1 因为分区数量和topic 0 一样,所以每个消费者能分到的最大分区数量也是一样的。

如果达到了上限,后面再分配分区就直接跳过此consumer。对于,consumer 1,它已经分配不到分区了。

topic0-1的第二个分区的分配流程:

由于consumer 0 所在的rack: rack 0 和 topic 0 以及 topic 1 的 partition 1 所在的rack都不一样,因此这里不将 partition 1 分配给 consumer 0。而consumer 1 也是类似的情况,所以两个topic的partition 1 不会分配给任何一个consumer。

topic0-1的第三个分区的分配流程:

与第二个分区情况类似,所以两个topic的partition 2 也不会分配给任何一个consumer。

综上所述,Rack Aware机制还是比较严格的,如果一个consumer订阅了多个topic,而多个topic的分区数量又一样的话,每个topic同样编号的分区要想分配给该consumer,此conusmer所在的rack必须要和这些同样编号的分区的所有副本所在的rack中至少有一个是相同的。其中有哪一个topic的分区的副本的rack中没有和该conusmer的rack一样,就不会分配给它任何一个topic的对应编号的分区。

后续再分配

经过Rack Aware分配历程后,consumer 1 分配到了 topic0-1的 partition 0,对于topic0-1,分别都能再分到1个分区。 conusmer 0 则是一无所获。 接下来则是按照此前说明的未启用Rack Aware时的分配流程来进行分配剩下的分区了。相对来说简单的多,最终可以得到如下结果:

相关推荐
Edingbrugh.南空22 分钟前
Kafka线上集群部署方案:从环境选型到资源规划思考
分布式·kafka
萌新小码农‍23 分钟前
SpringBoot新闻项目学习day3--后台权限的增删改查以及权限管理分配
spring boot·后端·学习
我是老孙28 分钟前
Kafka节点注册冲突问题分析与解决
分布式·kafka
leo_hush30 分钟前
kafka部署和基本操作
分布式·kafka
想用offer打牌1 小时前
一站式了解责任链模式🥹
后端·设计模式·架构
小码编匠1 小时前
面向工业应用的点云相机控制接口库(含C#调用示例)
后端·c#·.net
Luffe船长1 小时前
springboot将文件插入到指定路径文件夹,判断文件是否存在以及根据名称删除
java·spring boot·后端·spring
程序员清风3 小时前
RocketMQ发送消息默认是什么策略,主同步成功了就算成功了?异步写?还是要大部分从都同步了?
java·后端·面试
罗政3 小时前
小区物业管理系统源码+SpringBoot + Vue (前后端分离)
vue.js·spring boot·后端
杨同学technotes3 小时前
Spring Kafka进阶:实现多态消息消费
后端·kafka