【问题标题】:Custom Partitioner for Plain Producer | Kafka StreamsPlain Producer 的自定义分区器 |卡夫卡流
【发布时间】:2020-02-03 14:38:40
【问题描述】:

我有一个 kafka 流应用程序,它有

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

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

这是一个在kafka 2.4版本中即使使用相同的key也可以将消息分发到不同分区的类

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() {
    }
}

我的 Partitioner 包含完全相同的代码但不同的分区方法实现,我的代码块是:

    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;

    }

当我像这样配置时,消息被分发到不同的分区,在这两种实现中,但从不使用某些分区。

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

编辑 1: 我已经尝试使用普通生产者使用 RoundRobinPartitioner。结果是一样的。 Producer 不能在 partition 中产生同样的消息,有些 partition 是从不使用的。可能是什么原因 ?这不像是缺少配置。

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

partition() 方法在我找不到的地方被调用。

编辑 3:这可能与我没有覆盖的 onNewBatch 方法有关吗?

编辑 4: 此实现适用于 kafka 客户端 2.2,但不适用于 2.4。分区接口没有 onNewBatch 方法。当 key 为 null 2.2 vs 2.4 时,DefaultPartitioner 的实现发生了变化。会不会和条形分区有关?

【问题讨论】:

  • 嗯。那么,每条消息是否都有不同的密钥?
  • 您的课程是否扩展了 RoundRobinPartitioner?
  • 不,它们都有相同的密钥,但这有关系吗?因为我只是用 AtomicInteger 返回 getAndIncrement,所以消息会发送到该分区。我的类扩展了 Partitioner 类
  • 当使用内置RoundRobinPartitioner并使用same键发送消息时;它们是放在不同的分区吗?
  • 不,它们被放置在同一个分区中,没有任何改变

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


【解决方案1】:

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

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

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

【讨论】:

  • 是的,这正是我的问题!当我写这个问题时,它是 2 月 :) 我将其标记为答案,谢谢 Matthias
  • 我在这个问题上花了 2 天的时间疯了,谢谢! :)
猜你喜欢
  • 1970-01-01
  • 2018-01-15
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-06
相关资源
最近更新 更多