在Apache Kafka中,为什么不能有比分区更多的消费者实例?

时间:2014-09-17 16:48:18

标签: distributed apache-kafka

我正在学习Kafka,阅读这里的介绍部分

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

特别是关于消费者的部分。在引言的倒数第二段中,它读到

  

卡夫卡做得更好。通过在主题中具有并行性概念 - 分区 - 卡夫卡是       能够在消费者流程池中提供订购保证和负载平衡。这个       通过将主题中的分区分配给使用者组中的使用者来实现       每个分区仅由组中的一个消费者使用。通过这样做,我们确保了       使用者是该分区的唯一读者并按顺序使用数据。既然有很多       分区仍然可以平衡许多消费者实例的负载。但请注意,不可以       消费者实例多于分区。

我的困惑源自最后一句话,因为在该段落的正上方,作者描绘了两个消费者群体和一个4分区主题,消费者实例多于分区!

与分区相比,消费者实例不会更多,这也没有意义,因为分区将非常小,似乎为每个消费者实例创建新分区的开销会让人感到困难卡夫卡我知道分区用于容错并减少任何一台服务器上的负载,但上述句子在分布式系统的上下文中没有意义,该分布式系统应该能够处理数千个消费者。时间。

6 个答案:

答案 0 :(得分:52)

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

  1. 为了提供订购总订单,消息只能发送给一个消费者。否则它将是非常低效的,因为它需要等待所有消费者在发送下一个消息之前收到消息:
  2.   

    然而,虽然服务器按顺序分发消息,但消息是异步传递给消费者的,因此它们可能会在不同的消费者上无序传送。这实际上意味着在并行消费的情况下消息的排序会丢失。消息系统通常通过拥有“排他性消费者”的概念来解决这个问题。只允许一个进程从队列中消耗,但这当然意味着处理中没有并行性。

         

    卡夫卡做得更好。通过在主题中具有并行性概念 - 分区 - ,Kafka能够在消费者流程池中提供订购保证和负载平衡。这是通过将主题中的分区分配给使用者组中的使用者来实现的,以便每个分区仅由该组中的一个使用者使用。通过这样做,我们确保使用者是该分区的唯一读者并按顺序使用数据。由于有许多分区,这仍然可以平衡许多消费者实例的负载。但请注意,除了分区之外,不能有更多的消费者实例。

         

    Kafka仅对分区内的邮件提供总订单,而不是在主题中的不同分区之间。

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

    1. 图片显示了不同的消费者群体,但每个分区最多一个消费者的限制仅在一个群组内。您仍然可以拥有多个消费者群体。
    2. 最初描述了两种情况:

        

      如果所有消费者实例都具有相同的消费者群体,那么这就像传统的队列平衡消费者的负担一样。

           

      如果所有消费者实例都有不同的消费者群体,那么这就像发布 - 订阅一样,并且所有消息都会广播给所有消费者。

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

      另一方面,组越少,你拥有的分区就越多,你就可以通过平行化消息处理获得更多。

答案 1 :(得分:5)

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

我想这句话

  

但请注意,除了分区之外,不能有更多的消费者实例。

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

我认为这是因为,至少在Kafka 0.9.x中,没有什么可以防止有多个消费者实例,同一组的成员从同一个分区读取。

你可以在两个或多个不同的线程中做这样的事情

picture

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

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

如果两个消费者同时读取当前的偏移量,那么它们都将读取相同的值,并且它们都会得到相同的消息。

如果您希望每个消费者阅读不同的消息,您将不得不同步它们,因此只有一个消费者可以在时间获取并提交偏移量。

答案 2 :(得分:2)

Kafka无法为每个分区支持多个消费者。

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

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

如果多个消费者正在从同一分区读取,则消费者1从偏移0-4096的文件读取,但消费者2仍将尝试从偏移0读取,除非它还接收发送给消费者1的消息。 现在,如果向多个消费者发送相同的消息而不是负载平衡,那么Kafka已将它们划分为消费者组,因此所有消费者组都可以接收消息,但在消费者组内,只有一个消费者可以接收消息。

答案 3 :(得分:1)

In Kafka, only one consumer instance can consume messages from a partition. If consumer instances are more than partitions, then there will be no use of extra consumer instances. So kafka don't allow these extra consumer instances.

Now, If multiple consumers can consume partition then there would not be any ordering in consumption of messages. This is the reason why kafka don't allow multiple consumers per partition

答案 4 :(得分:0)

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

考虑以下示例:

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

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

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

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

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

希望这很有道理。

答案 5 :(得分:-1)

消费者组可以具有特定主题所需的任意数量的实例,但是,该主题的额外实例(即>已订阅的主题中分区的数量)将处于空闲状态。

反过来说,如果同一个消费者群体已经订阅了多个不同的主题,每个主题都有不同的编号,该怎么办?分区。

现在,您可以仅基于任一主题在使用者组上应用实例==分区,对吗?

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

示例:

  • 具有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个分区。