主题、分区和键

Topics, partitions and keys

我正在寻找有关该主题的一些说明。 在 Kafka 文档中,我发现了以下内容:

Kafka 仅提供分区内消息的总顺序,而不是主题中不同分区之间的消息。对于大多数应用程序来说,按分区排序与按键分区数据的能力相结合就足够了。但是,如果您需要对消息进行总排序,这可以通过只有一个分区的主题来实现,尽管这意味着每个消费者组只有一个消费者进程。

所以这是我的问题:

  1. 这是否意味着如果我想让超过 1 个消费者(来自同一组)阅读一个主题,我需要有超过 1 个分区?

  2. 这是否意味着我需要与同一组的消费者数量相同的分区数量?

  3. 一个分区可以读取多少消费者?

关于API,还有一些关于键和分区之间关系的问题。我只看了 .net APIs(尤其是来自 MS 的),但看起来像模仿的 Java API。 我看到当使用生产者向主题发送消息时有一个关键参数。但是当消费者从一个主题中读取时,会有一个分区号。

  1. 分区是如何编号的?从 0 还是 1 开始?
  2. 键和分区到底是什么关系? 据我了解,键上的某些功能将确定一个分区。对吗?
  3. 如果我在一个主题中有 2 个分区,并且希望一些特定的消息进入一个分区而其他消息进入另一个分区,我应该为一个特定的分区使用特定的密钥,而其余的则为另一个?
  4. 如果我有 3 个分区,一种类型的消息发送到一个特定分区,其余的发送到其他 2 个分区怎么办?
  5. 通常我如何将消息发送到特定分区以便让消费者知道从哪里阅读? 或者我最好有多个主题?

提前致谢。

分区增加了 Kafka 主题的并行度。任意数量的 consumers/producers 可以使用同一个分区。由应用层来定义协议。 Kafka 保证交付。关于 API,您可能需要查看 Java 文档,因为它们可能更完整。根据我的经验:

  1. 分区从0开始
  2. 密钥可用于将消息发送到同一分区。例如 hash(key)%num_partition。逻辑可插入生产者。 https://kafka.apache.org/090/javadoc/index.html?org/apache/kafka/clients/producer/Partitioner.html
  3. 是的。但要注意不要以某些会导致“专用”分区的密钥结束。为此,您可能需要专门的主题。例如控制主题和数据主题
  4. 这好像和3是同一个问题
  5. 我认为消费者不应该根据分区对数据进行假设。典型的方法是让消费者组可以从一个主题的多个分区中读取。如果你想有专门的频道,最好(safer/maintainable)使用单独的主题。

Does it mean if i want to have more than 1 consumer (from the same group) reading from one topic I need to have more than 1 partition?

让我们看看kafka的以下属性:

  • 每个分区只被组中的一个消费者消费
  • 组中一个消费者可以消费多个分区
  • 一个组中的消费者进程数必须<=个数 分区数

凭借这些属性,kafka 能够巧妙地在消费者进程池中提供 ordering guaranteesload balancing

回答你的问题,是的,在同一组的情况下,如果你想有N consumers,你必须有at least N partitions

Does it mean I need same amount of partitions as amount of consumers for the same group?

我想这在第一个答案中已经解释过了。

How many consumers can read from one partition?

可以从一个分区读取的 number of consumers 始终等于订阅该主题的 number of consumer groups

Relationship between keys and partitions with regard to API

首先,我们必须了解 producer 负责选择将哪条记录分配给主题内的哪个分区。

现在,让我们看看生产者是如何做到的。首先,让我们看看 ProducerRecord.java 的 class 定义:

public class ProducerRecord<K, V> {

    private final String topic;
    private final Integer partition;
    private final Headers headers;
    private final K key;
    private final V value;
    private final Long timestamp;

}

这里,我们要从class中理解的字段是partition

来自ProducerRecord docs

  • 如果指定了有效的partition number,发送记录时将使用partition
  • 如果未指定分区但存在 key,将使用 hash of the key.
  • 选择分区
  • 如果 keypartition 都不存在,将在 round-robin fashion.
  • 中分配一个分区