首页 文章

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

提问于
浏览
39

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

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

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

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

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

没有比分区更多的消费者实例也没有意义,因为那时分区将非常小,并且看起来为每个消费者实例创建新分区的开销会使Kafka陷入困境 . 我知道分区用于容错并减少任何一台服务器上的负载,但上述句子在分布式系统的环境中没有意义,该分布式系统应该能够一次处理数千个消费者 .

5 回答

  • 0

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

    我猜这句话

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

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

    我假设,因为,至少对于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);
    

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

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

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

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

  • 1

    在Kafka中,只有一个消费者实例可以使用来自分区的消息 . 如果使用者实例不仅仅是分区,那么就不会使用额外的使用者实例 . 所以kafka不允许这些额外的消费者实例 .

    现在,如果多个消费者可以使用分区,那么消费消息就不会有任何排序 . 这就是为什么kafka不允许每个分区有多个用户的原因

  • 3

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

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

    但是,尽管服务器按顺序分发消息,但消息是异步传递给消费者的,因此它们可能会在不同的消费者上无序传送 . 这实际上意味着在存在并行消耗的情况下消息的排序会丢失 . 消息传递系统通常通过具有“独占消费者”概念来解决这个问题,该概念只允许一个进程从队列中消耗,但当然这意味着处理中没有并行性 . Kafka 做得更好 . 通过在主题中具有并行性概念 - 分区 - ,Kafka能够在消费者流程池中提供订购保证和负载 balancer . 这是通过将主题中的分区分配给使用者组中的使用者来实现的,以便每个分区仅由该组中的一个使用者使用 . 通过这样做,我们确保使用者是该分区的唯一读者并按顺序使用数据 . 由于有许多分区,这仍然可以 balancer 许多消费者实例的负载 . 但请注意,除了分区之外,不能有更多的消费者实例 . Kafka仅提供分区内消息的总订单,而不是主题中不同分区之间的消息 .

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

    • 图片显示不同的消费者群体,但每个分区最多一个消费者的限制仅在一个群组内 . 您仍然可以拥有多个消费者群组 .

    最初描述了两种情况:

    如果所有消费者实例都具有相同的消费者群组,那么这就像传统的队列 balancer 对消费者的负载一样 . 如果所有消费者实例具有不同的消费者组,则其工作方式类似于发布 - 订阅,并且所有消息都广播给所有消费者 .

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

    另一方面,较少的组,您拥有的分区越多,您从平均消息处理中获得的越多 .

  • 43

    Kafka无法为每个分区支持多个消费者是有原因的 .

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

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

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

  • 0

    Kafka使用者组模型是排队机制的混合体,其中一个消费者实例读取的消息立即从队列中删除,而pub / sub机制则消息未被删除,直到保留期设置或直到它到期并且可用于所有消费者实例,直到到期 . 因此,如果您有要使用的用例,即pub / sub模型,但希望将其用作排队机制,则可以为所有使用者实例创建使用者组 . 鉴于Kafka在单个使用者组中的消费者实例之间分配分区,因此可确保仅处理一条消息 . 如果Kafka允许您在单个消费者组中拥有更多的消费者实例,那么它就会超过拥有消费者群体的目的 .

    考虑这个例子:

    REST API pub1向topic1发布了4条消息,其中包含4个分区part1至part4,因此每个部分都有1条消息 .

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

    现在,如果您创建2个使用者组,则每个miroservice sub1instance1将映射到part1,sub1instance2将映射到part2等 . 类似,sub2instance1将映射到part1,sub2instance2将映射到part2等 .

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

    如果消费者实例多于分区,那么Kafka必须将相同的分区分配给多个消费者实例,这样消息将被映射到该分区的每个消费者实例多次处理 . 这就是为什么Kafka阻止我们在消费者群组中拥有更多消费者实例而不是消费者群体订阅的主题内的分区数量的原因 .

    希望这是有道理的 .

相关问题