kafka消费者(四):PartitionAssignor

本文深入探讨了Kafka中Leader消费者如何根据PartitionAssignor接口实现的分区分配策略进行分区分配,包括分配策略的原理、关键类如Subscription和Assignment的作用,以及用户如何通过自定义数据控制分配结果。

Leader消费者在受到JoinGroupResponse之后,会按照其中指定的分区分配策略进行分区分配,每个分区分配策略即使一个PartitionAssignor接口的实现。
PartitionAssignor定义了Assignment和Subscription两个内部类。进行分区分配需要两方面的数据,metadata中记录的集群元数据和每个member的订阅信息。为了用户增强对分配结果的控制,就将用户订阅信息和一些影响分配的用户自定义信息封装成Subscription。例如,“用户自定义数据”可以是每个消费者的权重,在分配时可以根据此分配分区。其中,topics集合表示某个Member订阅的topic集合,userData表示用户自定义的数据。PartitionAssignor接口提供了subscription()方法,用户添加用户自定义数据,在创建JoinGroupRequest的时候回调用subscription()方法。

Assginment中保存了分配的结果,partitions表示分配给某消费者的topicPartition集合,userData是用户自定义的数据。
再来看看PartitionAssignor的方法,assign()是子类实现的完成Partition分配的抽象方法。onAssignment()方法时在每个消费者受到Leader分配结果时的回调函数。

public abstract class AbstractPartitionAssignor implements PartitionAssignor {
    public Map<String, Assignment> assign(Cluster metadata, Map<String, Subscription> subscriptions) {
        Set<String> allSubscribedTopics = new HashSet<>();
        Map<String, List<String>> topicSubscriptions = new HashMap<>();
        //解析subscriptions集合,去除userData信息
        for (Map.Entry<String, Subscription> subscriptionEntry : subscriptions.entrySet()) {
            List<String> topics = subscriptionEntry.getValue().topics();
            allSubscribedTopics.addAll(topics);
            topicSubscriptions.put(subscriptionEntry.getKey(), topics);
        }
        //统计每个Topic分区个数
        Map<String, Integer> partitionsPerTopic = new HashMap<>();
        for (String topic : allSubscribedTopics) {
            Integer numPartitions = metadata.partitionCountForTopic(topic);
            if (numPartitions != null && numPartitions > 0)
                partitionsPerTopic.put(topic, numPartitions);
            else
                log.debug("Skipping assignment for topic {} since no metadata is available", topic);
        }
        //把分配分区具体逻辑委托给了assign()重载,由子类实现
        Map<String, List<TopicPartition>> rawAssignments = assign(partitionsPerTopic, topicSubscriptions);

        // 整理分区结果
        Map<String, Assignment> assignments = new HashMap<>();
        for (Map.Entry<String, List<TopicPartition>> assignmentEntry : rawAssignments.entrySet())
            assignments.put(assignmentEntry.getKey(), new Assignment(assignmentEntry.getValue()));
        return assignments;
    }
}

如果需要在自定义PartitionAssingor时需要使用userData控制分区分配结果,就不能直接继承AbstractPartitionAssignor,而需要直接实现PartitionAssignor接口。
RangeAssignor和RoundRobinAssignor都是Kafka提供的默认实现,前者根据顺序分配取模确定,后者partition进行字典排序,顺序轮训消费者。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值