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时的分配流程来进行分配剩下的分区了。相对来说简单的多,最终可以得到如下结果:

相关推荐
BingoGo5 分钟前
Laravel13 + Vue3 的免费可商用 PHP 管理后台 CatchAdmin V5.2.0 发布
后端·php·laravel
青春不流名25 分钟前
kafka 集成OAUTHBEARER认证的例子
分布式·kafka
洛豳枭薰28 分钟前
kafka重平衡导致的消息重复消费或者消息丢失
分布式·kafka
rannn_11129 分钟前
【Redis|高级篇1】分布式缓存|持久化(RDB、AOF)、主从集群、哨兵、分片集群
java·redis·分布式·后端·缓存
weixin_4080996733 分钟前
【实战教程】EasyClick 调用 OCR 文字识别 API(自动识别屏幕文字 + 完整示例代码)
前端·人工智能·后端·ocr·api·安卓·easyclick
添尹35 分钟前
Go语言基础之指针
开发语言·后端·golang
GreenTea10 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
我是大猴子12 小时前
Spring代理类为何依赖注入失效?
java·后端·spring
码事漫谈12 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
码农BookSea13 小时前
ReAct:让大模型学会边想边做
后端·ai编程