kafka消费者分区分配策略

分区分配策略

kafka消费者客户端提供了partition.assign-ment.strategy来设置消费者与订阅主题之间的分区分配策略。一共有三种分配策略RangeAssignor(默认策略)、RoundRobunAssignor、StickyAssignor
消费者客户端可以配置多个分配策略,彼此以逗号分割

RangeAssigor分配策略

按照消费者数量和分区数进行整除运算来获得一个跨度,按照跨度进行分配,保证分区均匀分配给消费者。n=分区数/消费者数量,m=分区数据%消费者数量,m个多余分区分配给前m个消费者,前m个消费者分配n+1个分区,后面的消费者分配n个分区
例:一共有两个消费者c0、c1和两个topict0、t1,t0和t1分别有三个分区,3/2 =1;3%2=1,所以c0承担t0里两个分区的消费和t1里两个分区的消费,最终消费结果为c0消费4个分区,c1消费两个分区,导致消费者分配分区不均匀的情况

RoundRobunAssignor分配策略

RoundRobunAssignor将消费者和消费者订阅的所有主题的分区按照字典排序,然后通过轮询依次将分区分配给消费者
例:一共有两个消费者c0、c1和两个topict0、t1,t0和t1分别有三个分区,则分区结果为c0:t0p0、t0p2、t1p1,c1:t0p1、t1p0、t1p2,相比RangeAssigor而言消费者分配到的分区更加均匀。
三个消费者c0、c1、c2和三个topict0、t1、t2分别有1、2、3个分区,c0订阅了t0、t1;c1订阅t0、t1;c3订阅了t0、t1、t2,分区分配结果如下:
c0:t0p0
c1:t1p0
c2: t1p1、t2p0、t2p1、t2p2

StickyAssignor分配策略

目的:1.分区尽可能均匀 2.再均衡时分配结果尽可能和上次相似。优点:重分配时可以减少不必要的分区移动。
例:三个消费者c0、c1、c2和三个topict0、t1、t2分别有1、2、3个分区,c0订阅了t0、t1;c1订阅t0、t1;c3订阅了t0、t1、t2,分区分配结果如下:
c0:t0p0
c1:t1p0、t1p1
c2: t2p0、t2p1、t2p2
假设c0被移除消费组,再均衡后的分区分配结果为
c1:t1p0、t1p1、t1p1
c2: t2p0、t2p1、t2p2

自定义分配分区

实现PartitionAssignor,subscription()、assign()、name()、onAssignment()
subscription为订阅的消费者
assign()为为消费者分配核心,放会List<消费者, List<主题分区>>
name 为自定义分配分区名称
消费者订阅每一个分区实现广播功能

import org.apache.kafka.clients.consumer.internals.AbstractPartitionAssignor;
import org.apache.kafka.common.TopicPartition;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class BroadcastAssignor extends AbstractPartitionAssignor {

    private Map<String, List<String>> consumersPerTopic(Map<String, Subscription> consumerMetadata) {
        Map<String, List<String>> res = new HashMap();
        Iterator var3 = consumerMetadata.entrySet().iterator();

        while(var3.hasNext()) {
            Map.Entry<String, Subscription> subscriptionEntry = (Map.Entry)var3.next();
            String consumerId = subscriptionEntry.getKey();
            Iterator var6 = subscriptionEntry.getValue().topics().iterator();

            while(var6.hasNext()) {
                String topic = (String)var6.next();
                put(res, topic, consumerId);
            }
        }

        return res;
    }
    @Override
    public Map<String, List<TopicPartition>> assign(Map<String, Integer> partitionsPerTopic, Map<String, Subscription> subscriptions) {
        // 获取每个主题有多少消费者订阅,key为主题
        Map<String, List<String>> consumersPerTopic = this.consumersPerTopic(subscriptions);
        Map<String, List<TopicPartition>> resultAssign = new HashMap<String, List<TopicPartition>>();
        // 获取消费者
        Iterator var5 = subscriptions.keySet().iterator();

        while(var5.hasNext()) {
            String memberId = (String)var5.next();
            resultAssign.put(memberId, new ArrayList());
        }

        var5 = consumersPerTopic.entrySet().iterator();

        while(true) {
            String topic;
            List consumersForTopic;
            Integer numPartitionsForTopic;
            do {
                if (!var5.hasNext()) {
                    return resultAssign;
                }

                Map.Entry<String, List<String>> topicEntry = (Map.Entry)var5.next();
                topic = topicEntry.getKey();
                consumersForTopic =  topicEntry.getValue();
                numPartitionsForTopic = partitionsPerTopic.get(topic);
            } while(numPartitionsForTopic == null);
            List<TopicPartition> partitions = AbstractPartitionAssignor.partitions(topic, numPartitionsForTopic);

            for(int i =0; i < consumersForTopic.size(); i++) {
                ((List)resultAssign.get(consumersForTopic.get(i))).addAll(partitions);
            }
        }
    }

    @Override
    public String name() {
        return "broadcast";
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值