在Apache Kafka中,为什么使用者实例不能多于分区?


74

我正在学习Kafka,请在此处阅读介绍部分

https://kafka.apache.org/documentation.html#introduction

特别是关于消费者的部分。在引言的倒数第二段中,其内容为

卡夫卡做得更好。通过在主题内具有并行性(即分区)的概念,Kafka能够在用户进程池中提供排序保证和负载均衡。这是通过将主题中的分区分配给消费者组中的消费者来实现的,以便每个分区都由组中的一个消费者完全消费。通过这样做,我们确保使用者是该分区的唯一读取器,并按顺序使用数据。由于存在许多分区,因此仍然可以平衡许多使用者实例上的负载。但是请注意,使用者实例不能超过分区。

我的困惑源于最后一句话,因为在该段右上方的图像中,作者描述了两个消费者组和一个4分区主题,消费者实例多于分区!

消费者实例不能超过分区也没有意义,因为那样分区就会非常小,并且似乎为每个消费者实例创建新分区的开销会使Kafka陷入困境。我知道分区用于容错并减少任何一台服务器上的负载,但是上面的句子在分布式系统的背景下是没有意义的,该系统应该能够同时处理数千个消费者。

Answers:


74

好的,要理解它,就需要理解几个部分。

  1. 为了提供订购总订单,该消息只能发送给一位消费者。否则,它将效率极低,因为它将需要等待所有使用者接收到该消息,然后再发送下一条消息:

但是,尽管服务器按顺序分发消息,但是消息是异步传递给使用者的,因此它们可能会在不同的使用者上无序到达。这有效地意味着在存在并行消耗的情况下,消息的顺序丢失。消息传递系统通常通过具有“专用使用者”的概念来解决此问题,该概念仅允许一个进程从队列中使用,但是,这当然意味着在处理中没有并行性。

卡夫卡做得更好。通过在主题内具有并行性(即分区)的概念,Kafka能够在用户进程池中提供排序保证和负载均衡。这是通过将主题中的分区分配给消费者组中的消费者来实现的,以便每个分区都由组中的一个消费者完全使用。通过这样做,我们确保使用者是该分区的唯一读取器,并按顺序使用数据。由于存在许多分区,因此仍然可以平衡许多使用者实例上的负载。但是请注意,使用者实例不能超过分区。

Kafka仅按分区内的消息(而不是主题中不同分区之间的消息)提供总顺序。

您还认为性能损失(多个分区)实际上是性能的提高,因为Kafka可以完全并行地执行不同分区的操作,同时等待其他分区完成。

  1. 图片显示了不同的使用者组,但是每个分区最多只能有一个使用者的限制仅在一个组内。您仍然可以有多个消费者组。

首先,描述了两种情况:

如果所有使用者实例都具有相同的使用者组,则这就像在使用者上使用传统队列平衡负载一样。

如果所有使用者实例具有不同的使用者组,则此工作类似于发布-订阅,并且所有消息都广播给所有使用者。

因此,您拥有的订户组越多,性能就越低,因为kafka需要将消息复制到所有这些组并保证总​​订单。

另一方面,组越少,分区越多,从并行化消息处理中获得的收益就越大。


31
因此,可以通过以下澄清来回答该问题:在单个使用者组中,使用者实例不能超过分区。
almel 2014年

@peter“尽管服务器按顺序分发消息”:kafka服务器如何将消息分发给使用者。我当时在想,由于偏移量由消费者维护,因此消费者从kafka主题中获取消息。还是就像消费者告诉kafka到读取的内容,kafka将数据推送给消费者。我的真正问题是,kafka push是否基于?还是基于拉?
vishnu viswanath 16/09/22

@peter不错的答案,但是有一件重要的事情没有解决。如果我们希望每个消费者仅分配一个分区怎么办?这将意味着一个组中的分区和使用者数量相等(如果Kafka进行了适当的平衡,并且做到了)。好的,现在我们还要确保即使某些使用者实例发生故障,每个使用者实例仍具有一个分区。这样做的逻辑方法是将更多的消费者添加到该组中。虽然一切正常,但是他们什么也不会做,但是当某些使用者失败时,其中一个会收到该分区。为什么不允许这样做?
Miljen Mikic

@peter“因此,您拥有的订户组越多,性能越低,因为kafka需要将消息复制到所有这些组并保证总​​订单。” 在这种情况下,等待时间相对于消费者群体的数量是线性的还是次线性的?
Novemberland

1
@Miljen Mikic就是这样,多个使用者被保留为冗余,并且在主要使用者失败的情况下,其他使用者将被随机分配到相应的分区。
Prashant

6

重要的是要记住,Kafka每个[消费者组,主题,分区]都保留一个偏移量。这就是原因。

我猜这句话

但是请注意,使用者实例不能超过分区。

指的是“自动使用者组重新平衡”模式,这是当您只将一些使用者订阅()到主题列表时的默认使用者模式。

我认为这是因为,至少对于Kafka 0.9.x,没有什么可以阻止多个使用者实例(即同一组的成员)从同一分区读取数据。

您可以在两个或多个不同的线程中执行类似的操作

Properties props = new Properties();
props.put(ConsumerConfig.GROUP_ID_CONFIG, "MyConsumerGroup");
props.put("enable.auto.commit", "false");
consumer = new KafkaConsumer<>(props);
TopicPartition partition0 = new TopicPartition("mytopic", 0);
consumer.assign(Arrays.asList(partition0));
ConsumerRecords<Integer, String> records = consumer.poll(1000);

并且您将有两个(或更多)消费者从同一个分区读取。

现在,“问题”是两个使用者将共享相同的偏移量,您没有其他选择,因为只有一个组,主题和分区在起作用。

如果两个使用者都同时读取当前偏移量,那么他们两个将读取相同的值,并且他们都将收到相同的消息。

如果要让每个使用者阅读不同的消息,则必须同步它们,以便一次只能获取并提交偏移量。


3

Kafka不能为每个分区支持多个使用者是有原因的。

Kafka代理将数据写入每个分区的文件中。因此,假设配置了两个分区,代理将创建两个文件,并分配多个可以将消息发送到的使用者组。

现在,对于每个分区,只有一个使用者使用基于文件偏移量的消息。例如,消费者1将首先从文件偏移量0到4096读取消息。现在,这些偏移量是有效负载的一部分,因此消费者将知道在请求下一条消息读取时使用哪个偏移量。

如果多个使用者正在从同一分区读取,那么使用者1将读取偏移量为0-4096的文件,但是使用者2仍将尝试从偏移量0读取,除非它也接收到发送给使用者1的消息。它不是负载平衡,因此Kafka已将其分为消费者组,因此所有消费者组都可以接收消息,但是在消费者组中,只有一个消费者可以接收消息。


1
您说Kafka每个分区不能有多个使用者。如果C1和C2来自不同的使用者组,是否可以从同一分区读取?我认为他们必须有能力,否则Kafka会有效地使用排他性使用者(特定分区排他性)方法,并且您不会获得负载平衡。听到您的声音,Kafka在区分不同消费者群体的消费者方面实际上在做什么,这将非常有帮助。同样,由于Kafka将数据写入磁盘,因此如果写入不再是线性的,那么拥有来自不同组的多个使用者似乎真的很慢。
almel

2

在Kafka中,只有一个使用者实例可以使用分区中的消息。如果使用者实例多于分区,则不会使用额外的使用者实例。因此,kafka不允许这些额外的使用者实例。

现在,如果多个使用者可以使用分区,那么消息的使用将没有任何顺序。这就是为什么kafka不允许每个分区有多个使用者的原因


2

Kafka消费者组模型是一种排队机制的混合,其中一个消费者实例曾经读取过的消息会立即从队列中删除,而pub / sub机制是直到保留时间设置或到期后才删除该消息并可供使用的pub / sub机制。所有消费者实例,直到到期为止。因此,如果您有要使用的发布/订阅模型,但又想将其用作排队机制,则可以为所有使用者实例创建使用者组。给定Kafka在单个使用者组中的使用者实例之间分配分区,可以确保仅处理一次消息。如果Kafka允许您在一个消费者群体中拥有更多消费者实例,那么它将超越拥有消费者群体的目的。

考虑以下示例:

REST API pub1将4条消息发布到topic1,该消息具有4个分区part1到part4,因此每个部分都有1条消息。

您有2个微服务sub1和sub2作为订阅者,每个微服务有4个实例在运行。

现在,如果您创建2个使用者组,则每个miroservice的一个sub1instance1将被映射到part1,sub1instance2将被映射到part2,依此类推,sub2instance1将被映射到part1,sub2instance2被映射到part2,等等。

只要您在每个使用者组中的使用者实例小于或等于分区数,您的微服务的每个实例将只处理一次消息。在这种情况下,sub1instance1和sub2instance将处理来自part1的msg1。

如果使用方实例的数量超过分区数量,那么Kafka将必须将相同的分区分配给多个使用方实例,以便映射到该分区的每个使用方实例将多次处理消息。这就是为什么Kafka阻止我们在用户组中拥有的用户实例数量超过用户组所订阅主题中的分区数量的原因。

希望这是有道理的。


确实有道理。我想知道为什么这个答案没有足够的支持。
Tushar

0

消费者组可以具有特定主题所需的尽可能多的实例,但是,多余的实例对于该主题将是空闲的。在这里,额外的实例是指实例>否。订阅的主题中的分区数。

换个角度来看,我们知道同一个消费者群体可以订阅多个主题,对吗?现在,如果订阅的每个主题都具有不同的编号,该怎么办?的分区,有可能吧?

因此,您可以申请{否。实例==否。订阅者主题中的任何一个仅基于消费者群体的分区理论}对吗?

因此,实际上,您至少希望没有。的实例等于否。具有特定主题的分区,但是如果有更多主题,则对该主题没有害处,多余的实例将保持空闲状态。

例:

  • 具有2个分区的主题A
  • 具有3个分区的主题B
  • 具有3个实例的消费者组

     A[1 2]   B[1 2 3]
    
         [x y z] (consumer group)
    

现在,对于主题“ B”,所有3个消费者实例都将处于活动状态(每个从1个分区读取),但是,对于主题“ A”,只有3个消费者实例中的任意2个处于活动状态(即,其中1个消费者实例将处于空闲状态)只有2个分区)。


@anonymous请提供(-1)的推论,以便通过给定的答案/解释帮助我(每个人)理解您的关注?
sactiw
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.