java - kafka 中的每条消息使用不同的 key

标签 java apache-kafka kafka-producer-api

我们在 Java 中有一个 kafka 生产者-消费者设置(使用 spring-kafka,但可能与这里无关)。使用的键是String,值是自定义 POJO。生产者-消费者通过具有 16 个分区的单个主题 test-topic 进行通信。 Consumer的并发度为16,因此可以并行读取每个分区。

从文档和其他引用资料中,我了解到 - 使用 null 键将以循环方式在分区中分发发布者发送的消息。如果我有兴趣将消息分发到使用键派生的特定分区,建议使用非空键

我有以下疑问 -

  1. 目前,生产者为每条消息发送唯一的 key 。由于这是每条消息的唯一String,因此在几乎所有情况下,它也会生成唯一的哈希码。消息将如何在这里分发,是否会像 null 键那样进行循环,或者重复使用分区或任何其他控制机制的某些哈希逻辑?
  2. null 键相比,使用上述策略的键有什么优点或缺点?
  3. 我不需要维护消息的顺序或分组。在这种情况下,使用 null 键是否明智,或者每条消息拥有唯一或非唯一非空键仍然很好,如果是,为什么?
  4. 消费者正在批量读取消息。有或没有关键影响批量读取与单个读取是否不同?

最佳答案

Kafka生产者基于DefaultPartitioner、自定义分区器将消息发送到特定分区,或者在发送消息时传递分区信息以写入特定分区。 将键定义为 null 或非 null 取决于您的用例和需求,但主要目的是将消息分发到不同的分区上,以供消费者组的多个消费者使用。

非空键确保相似的键将停放在同一分区上,这将帮助您将同一存储桶上的多个相似键分组以供进一步的分析,同时空键使您均匀地分发消息。

非空键始终有助于传递消息的元详细信息以供进一步处理。我希望通过自定义分区器传递非空键来控制消息流。但这取决于具体要求,如果您想传递 null 键,那绝对没问题。

Note: In future release Apache Kafka (2.5) you can able to define RoundRobin partitioner as partition strategy(KIP-369) which not needed to the key to be null. https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=89070828

  1. 如果您未定义自定义分区程序,它将使用默认分区程序

在 Apache Kafka 2.4 之前,它将经历一个又一个循环并将记录发送给每个循环。 在这种情况下,Apache Kafka 2.4 之前的旧分区策略是循环遍历主题的分区并向每个分区发送一条记录。 但是,正如您所了解的那样,消息作为带有配置参数 linger.ms 的批处理进行,它可能会对小批量的性能产生影响,因为每个消息都会进入特定的分区,因此 Apache Kafka 引入了新的粘性分区器,以防空键的情况

Apache Kafka 在 Apache Kafka 2.4 中引入了 Sticky Partitioner(KIP-480),以防默认分区器中的 key null ,如下所述

粘性分区策略

粘性分区器通过选择单个分区来发送所有非键记录,解决了将没有键的记录分散成较小批处理的问题。一旦该分区的批处理被填满或以其他方式完成,粘性分区器就会随机选择并“粘贴”到新的分区。这样,在较长的一段时间内,记录大约均匀分布在所有分区中,同时获得较大批量大小的额外好处。

enter image description here

Please click here for more detail

  • 如果传递非空键且未定义自定义分区器,则会使用 DefaultPartitioner 来标识分区来发布消息。 DefaultPartitioner 使用 MurmurHash,这是一种非加密哈希函数,通常用于基于哈希的查找。然后将该哈希用于模运算 (% numPartitions),以确保返回的分区在 [0, N] 范围内,其中 N 是主题的分区数。

    返回 Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;

  • 您还可以定义自定义分区程序并实现选择分区的逻辑 https://kafka.apache.org/10/javadoc/org/apache/kafka/clients/producer/Partitioner.html

  • 发布消息时显式传递分区

    /** * 创建一条记录发送到指定主题和分区 */ public ProducerRecord(字符串主题,整数分区,K键,V值) { this(主题,分区,空,键,值,空); }

  • 关于java - kafka 中的每条消息使用不同的 key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62623654/

    相关文章:

    node.js - 如何在 Node JS 中向多个 Kafka 主题分区发送数据

    java - 卡夫卡 : Alter number of partitions for a specific topic using java

    java - Hibernate实体没有PK但有FK

    java - 标记 "]"出现语法错误,此标记后应有 VariableDeclaratorld

    java - IBM Bluemix : How the deploy an application on Bluemix?

    apache-kafka - 类路径为空。请先构建项目

    java - 如何使用 oAuth/http header 用户名和密码保护 Nexmo 回调 URL

    容器启动时应用程序错误地解析了 Docker 别名

    apache-kafka - 卡夫卡连接 : How can I send protobuf data from Kafka topics to HDFS using hdfs sink connector?

    java - Apache 卡夫卡 : how to find difference between queue and pub/sub programatically