详解kafka中的消息分区分配算法
作者:温故知新之java 发布时间:2021-06-02 08:16:15
背景
kafka有分区机制,一个主题topic在创建的时候,会设置分区。如果只有一个分区,那所有的消费者都订阅的是这一个分区消息;如果有多个分区的话,那消费者之间又是如何分配的呢?
分配算法
RangeAssignor
定义
Kafka默认采⽤RangeAssignor的分配算法。
RangeAssignor策略的原理是按照消费者总数和分区总数进⾏整除运算来获得⼀个跨度,然 后将分区按照跨度进⾏平均分配,以保证分区尽可能均匀地分配给所有的消费者。对于每⼀个 Topic,RangeAssignor策略会将消费组内所有订阅这个Topic的消费者按照名称的字典序排序,然 后为每个消费者划分固定的分区范围,如果不够平均分配,那么字典序靠前的消费者会被多分配 ⼀个分区。
这种分配⽅式明显的⼀个问题是随着消费者订阅的Topic的数量的增加,不均衡的问题会越来 越严重,⽐如上图中4个分区3个消费者的场景,C0会多分配⼀个分区。如果此时再订阅⼀个分区 数为4的Topic,那么C0⼜会⽐C1、C2多分配⼀个分区,这样C0总共就⽐C1、C2多分配两个分区 了,⽽且随着Topic的增加,这个情况会越来越严重。
源码分析
public class RangeAssignor extends AbstractPartitionAssignor {
....
@Override
public Map> assign(Map partitionsPerTopic, Map subscriptions) {
// 1. 获取每个topic被多少个consumer订阅了
Map<String,List<String>> consumersPerTopic = consumersPerTopic(subscriptions);
// 2. 存储最终的分配⽅案
Map<String,List<String>> assignment = new HashMap<>();
for (String memberId : subscriptions.keySet())
assignment.put(memberId, new ArrayList());
for (Map.Entry> topicEntry : consumersPerTopic.entrySet()) {
String topic = topicEntry.getKey();
List consumersForTopic = topicEntry.getValue();
// 3. 每个topic的partition数量
Integer numPartitionsForTopic = partitionsPerTopic.get(topic);
if (numPartitionsForTopic == null)
continue;
Collections.sort(consumersForTopic);
// 4. 表示平均每个consumer会分配到多少个partition
int numPartitionsPerConsumer = numPartitionsForTopic / consumersForTopic.size();
// 5. 平均分配后还剩下多少个partition未被分配
int consumersWithExtraPartition = numPartitionsForTopic % consumersForTopic.size();
List partitions = AbstractPartitionAssignor.partitions(topic, numPartitionsForTopic);
// 6. 这⾥是关键点,分配原则是将未能被平均分配的partition分配到前 consumersWithExtraPartition个consumer
for (int i = 0, n = consumersForTopic.size(); i < n; i++) {
int start = numPartitionsPerConsumer * i + Math.min(i, consumersWithExtraPartition);
int length = numPartitionsPerConsumer + (i + 1 > consumersWithExtraPartition ? 0 : 1); assignment.get(consumersForTopic.get(i)).addAll(partitions.subList(start, start + length));
}
}
return assignment;
}
}
场景
可以完全平均分配
无法完全平均分配,排序靠前分的更多
消费者数量大于分区数量,排名靠前先分得,排名靠后未分得分区
RoundRobinAssignor
定义
RoundRobinAssignor的分配策略是将消费组内订阅的所有Topic的分区及所有消费者进⾏排序后尽 量均衡的分配(RangeAssignor是针对单个Topic的分区进⾏排序分配的)。如果消费组内,消费者订阅 的Topic列表是相同的(每个消费者都订阅了相同的Topic),那么分配结果是尽量均衡的(消费者之间 分配到的分区数的差值不会超过1)。
源码分析
package org.apache.kafka.clients.consumer;
public class RoundRobinAssignor extends AbstractPartitionAssignor {
@Override
public Map> assign(Map partitionsPerTopic, Map subscriptions) {
<Map> assignment = new HashMap<>();
for (String memberId : subscriptions.keySet()) assignment.put(memberId, new ArrayList()); // 1. 环状链表,存储所有的consumer,⼀次迭代完之后⼜会回到原点
CircularIterator assigner = new CircularIterator<> (Utils.sorted(subscriptions.keySet())); // 2. 获取所有订阅的topic的partition总数 for (TopicPartition partition : allPartitionsSorted(partitionsPerTopic, subscriptions)) {
final String topic = partition.topic();
while (!subscriptions.get(assigner.peek()).topics().contains(topic))
assigner.next();
assignment.get(assigner.next()).add(partition);
}
return assignment;
}
.... }
场景
无法完全平均分配,排序靠前分的更多
StickyAssignor
定义
尽管RoundRobinAssignor已经在RangeAssignor上做了⼀些优化来更均衡的分配分区,但是在⼀些情况下依旧会产⽣严重的分配偏差,从字⾯意义上看,Sticky是“粘性的”,可以理解为分配结果是带“粘性的”——每⼀次分配变更相对 上⼀次分配做最少的变动(上⼀次的结果是有粘性的) 其⽬标有两点:
分区的分配尽量的均衡
每⼀次重分配的结果尽量与上⼀次分配结果保持⼀致
场景
来源:https://juejin.cn/post/7086656375685660708


猜你喜欢
- 描述:由于产品需求,要求含有EditText的界面全屏显示,最好的解决方式是使用AndroidBug5497Workaround.assis
- 实例如下:public class CustomScrollView extends ScrollView {private Gesture
- 本文实例讲述了C#串口通信实现方法。分享给大家供大家参考。具体方法如下:通过COM1发送数据,COM2接收数据。当COM2接收完本次发送的数
- lambda表达式以及并行流。官方承诺你写出来的代码更运行得更快。流会自动通过Fork/Join池并行地执行。我听过一些关于Java 8的主
- 调用微信接口前需要准备的内容。1.微信公众平台的appid2.微信公众平台的secret3..获取tokenid4.获取ticket5.生成
- 本文实例讲述了Java实现分解任意输入数的质因数算法。分享给大家供大家参考,具体如下:分解任意输入数的质因数:质因数概念:任何一个合数都可以
- 我们在C#编程中常见的信息提示框(MessageBox)是微软NET自带的一个用于弹出警告、错误或者讯息一类的“模式”对话框。此类对话框一旦
- 在上节使用了H2之后感觉很爽,很轻便,正好有个项目要求简单,最好不适用外部数据库,于是就想着把H2数据库集成进来,这个系统已经存在了一个Or
- Zxing是Google提供的关于条码(一维码、二维码)的解析工具,提供了二维码的生成与解析的方法,现在我简单介绍一下使用Java利用Zxi
- 环境:VS2019+Qt5.121. CLR库安装 &nb
- 什么是自动装箱和拆箱自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之
- 使用ProcessBuilder踩到的坑最近使用ProcessBuilder执行命令,命令内容正确,但始终报错命令实行失败,是因为不熟悉Pr
- 一 引入项目有个新需求,当点击或触碰TextBox时,基于TextBox的相对位置,弹出一个自定义的Keyboard,如下图所示:二 Key
- java代理有jdk * 、cglib代理,这里只说下jdk * ,jdk * 主要使用的是java反射机制(既java.lang.r
- 这篇文章主要介绍了SpringBoot以war包形式部署到外部Tomcat过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有
- 背景以springboot为tomcat启动的框架,以angular2为前端页面的框架,最后需要将angular2的代码运行在springb
- 本文实例为大家分享了Android自定义实现可滑动按钮的具体代码,供大家参考,具体内容如下实现逻辑1.创建一个类继承view类,实现里面的o
- springMVC默认的解析器里面是没有加入对文件上传的解析的,,使用springmvc对文件上传的解析器来处理文件上传的时需要用sprin
- 在编写脚本的过程中我们会遇到一些小问题比如一个的变量 为了在其他脚本中可以调用 我们需要写成public类型的这样的话在Inspector面
- 本文实例讲述了Java获取文件夹下所有文件名称的方法。分享给大家供大家参考,具体如下:import java.io.File;public