【问题标题】:KafkaProducer round-robin distribution not working for the same keyKafkaProducer 循环分发不适用于相同的密钥
【发布时间】:2018-01-16 15:10:27
【问题描述】:

我正在尝试了解 Kafka 的工作原理。我已经读过,默认情况下,Kafka 将在分区之间以循环方式分发来自生产者的消息。

但是,如果消息具有相同的键,为什么消息总是放在同一个分区中? (未配置分区键策略)。

例如,使用下面的代码,消息总是放在同一个分区中:

KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
String key = properties.getProperty("dev.id");
producer.send(new ProducerRecord<String, String>(properties.getProperty("kafka.topic"), key, value), new EventGeneratorCallback(key));

使用不同的密钥,消息以循环方式分发:

KafkaProducer<String, String> producer = new KafkaProducer<>(properties);
String key = properties.getProperty("dev.id") + UUID.randomUUID().toString();
producer.send(new ProducerRecord<String, String>(properties.getProperty("kafka.topic"), key, value), new EventGeneratorCallback(key));

【问题讨论】:

    标签: apache-kafka kafka-producer-api


    【解决方案1】:

    这正是 Kafka 生产者的工作方式。此行为由 DefaultPartitioner 类定义,您可以在官方 repo 中找到 here。 如果未指定键,则生产者使用循环方式在所有与主题相关的分区之间发送消息;如果指定了键,则分区器会处理键模块的散列和分区数,这样具有相同键的消息就会进入同一个分区。因为 Kafka 保证在分区级别(而不是主题级别)进行排序,所以这也是让所有具有相同键的消息在同一个分区中的一种方式,因此消费者按照它们发送的相同顺序接收。 最后,发送消息的另一种可能方式是生产者指定分区目标:在这种情况下,没有键,没有循环,但消息完全发送到生产者自己指定的分区。

    【讨论】:

    • 太好了!!因此,所谓的“键分区”策略无非就是传递给生产者的键以及生成的哈希将如何分配给给定的分区?!?!此外,这意味着我们无法进行分布式负载平衡。例如,我们最终可能会在一个分区中得到 1 个低容量流和 2 个高负载流共享另一个分区,而不是一个分区中 1 个低 + 1 个高,另一个分区中 1 个高,对吗?
    • 是的,但它是默认分区程序以这种方式运行。您可以编写自定义分区程序并使用不同的算法从键定义分区目标,该算法的含义取决于您的业务应用程序。
    • 感谢 ppatierno,您的回答比我的“编辑”要快,但它回答了我的问题。
    • 是“最后,发送消息的另一种可能方式是生产者指定分区目标。”是“低级 API”吗?
    • send 方法一起使用的ProducerRecord 类允许您提供分区。见这里:kafka.apache.org/21/javadoc/org/apache/kafka/clients/producer/…
    【解决方案2】:

    这是预期的行为。所有具有相同键的消息都放在同一个分区中。如果您希望对所有消息进行循环分配,则不应提供密钥。对于 Kafka 来说,拥有 key 的原因是为了将数据分布在各个分区中,而将相同的 key 放在不同的分区中会破坏这个契约。

    【讨论】:

      猜你喜欢
      • 2020-03-18
      • 2018-09-17
      • 2014-09-10
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多