普通生产者的自定义分区器| Kafka Streams

时间:2020-02-03 14:38:40

标签: java apache-kafka apache-kafka-streams

我有一个具有

的kafka流应用程序
props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, MyPartitioner.class);

props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, RoundRobinPartitioner.class);

这是一个用于在kafka 2.4版本中甚至使用相同密钥将消息分发到不同分区的类

RoundRobinPartitioner具有以下实现:

public class RoundRobinPartitioner implements Partitioner {
    private final ConcurrentMap<String, AtomicInteger> topicCounterMap = new ConcurrentHashMap();

    public RoundRobinPartitioner() {
    }

    public void configure(Map<String, ?> configs) {
    }

    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
        int numPartitions = partitions.size();
        int nextValue = this.nextValue(topic);
        List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
        if (!availablePartitions.isEmpty()) {
            int part = Utils.toPositive(nextValue) % availablePartitions.size();
            return ((PartitionInfo)availablePartitions.get(part)).partition();
        } else {
            return Utils.toPositive(nextValue) % numPartitions;
        }
    }

    private int nextValue(String topic) {
        AtomicInteger counter = (AtomicInteger)this.topicCounterMap.computeIfAbsent(topic, (k) -> {
            return new AtomicInteger(0);
        });
        return counter.getAndIncrement();
    }

    public void close() {
    }
}

我的分区程序由完全相同的代码组成,但分区方法的实现方式不同,我的代码块为:

    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
        List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);

        int numPartitions = partitions.size();

        int nextValue = nextValue(topic);

        return Utils.toPositive(nextValue) % numPartitions;

    }

当我像这样进行配置时,在两种实现方式中,消息均分配到不同的分区,但是从不使用某些分区。

My internal topic

我有50个分区,分区14和34从未收到消息。我的分区不是不可使用的。他们有空。当我将返回分区方法更改为14或34时,我所有的消息都转到该分区。可能是什么问题呢 ?两种实现方式均未按预期运行。

编辑1:我已经尝试过与普通生产者一起使用RoundRobinPartitioner。结果是一样的。生产者无法在分区之间平均产生消息,某些分区从未使用过。可能是什么原因 ?这不像缺少配置。

编辑2:我已调试RoundRobinPartitioner,并在返回处放置了一个断点。当我只产生1条消息时,生产者产生两次消息。第一次尝试总是失败,并且该消息不会进入任何分区。当我点击继续时,ConcurrentMap的调试索引将增加1。生产者的第二次尝试成功。

在我找不到的地方调用了

partition()方法。

编辑3:这是否与我未覆盖的onNewBatch方法有关?

编辑4::此实现仅适用于kafka客户端2.2,不适用于2.4。分区接口没有onNewBatch方法。当key为空2.2与2.4时,将更改DefaultPartitioner实现。它可以与棒状分区相关吗?

1 个答案:

答案 0 :(得分:0)

在kafka 2.4客户端版本中使用UniformStickyPartitioner.class。 RoundRobinPartitioner.class适用于kafka 2.2或更低版本。在2.4版本中

props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, UniformStickyPartitioner.class);

应该被使用。我认为这与新的StickPartitioner有关。