Kafka为什么在消息积压时不能直接通过消费者水平扩容来提升消费速度?

我们知道当消息生产者生产的速度快于消费者的消费速度时,会产生大量的消息积压,大多数人的想法是增加消费者的数量来提升消费速度,这个想法在RocketMQ中是可行的,但是在Kafka中不一定可行。为了更方便地分析问题,我们先忽略消费者组的设计,在增加消费者之前,架构设计,请看下图
Kafka为什么在消息积压时不能直接通过消费者水平扩容来提升消费速度?_第1张图片
一个topic下面建立了两个分区,partition-0和partition-1,分别被consumer-0和consumer-1消费,此时消息积压了很多,我们试图增加一个consumer-2,来增加partition的消费速度
Kafka为什么在消息积压时不能直接通过消费者水平扩容来提升消费速度?_第2张图片
你会发现消费速度没有变化,这是因为Kafka在一开始设计Parition的时候,就已经设计成了一个Parition在同一个时刻只能被一个Consumer消费,当消费者数量大于分区数量时,新加入的消费者是消费不到消息的,除非之前的分区数量是小于消费者数量,就像下图所示
Kafka为什么在消息积压时不能直接通过消费者水平扩容来提升消费速度?_第3张图片
Kafka之所以这样设计的原因有以下几点:

  • 保证分区局部有序性。一个分区同一时刻只能让一个消费者消费,这样有助于保证分区内的消息是有序的,能够实现在局部消息的顺序性,如果同时让多个消费者消费,必然会破坏分区的顺序性
  • 消费者组更好地协作和高吞吐。Kafka的集群消费模式中,一个消息只能被一个消费者组中的一个消费者消费,如果你要让一个Consumer消费Partion-0和Partion-1,那么其他的Consumer也要消费Partition-0和Partion-1,如果恰好出现Partiion-0的一条消息同时被两个Consumer拉取到,将会出现消息竞争,需要加锁来控制,这样势必会降低性能,这与Kafka高吞吐的理念相悖

所以在水平扩容消费者上面,相对RocketMQ来说不是那么地直接,在Kafka中需要做进一步考虑,多说一句,在RocketMQ中由于业务场景不同,相比Kafka处理的业务场景要复杂地多,所以RocketMQ需要支持消费者的水平扩容,这样就会出现消息竞争,但是为了水平扩容,RocketMQ需要这样做。

对比RocketMQ
RocketMQ在大多数情况下只会被同一个消费者组中的一个消费者实例消费,以保证消息的有序性。
但是在有些情况下,RocketMQ也支持消息负载均衡,即允许同一个MessageQueue被同一个消费者组中的多个消费者实例共同消费,

  • 消息负载均衡: 如果消费者组中存在一个实例处理速度较快,RocketMQ可能会将同一个MessageQueue分配给这个组中的其他相对较慢的实例,以实现负载均衡
  • 动态扩容:也就是我们讨论的动态增加消费者实例时,新加入的实例可能会被分配到已有实例所消费的MessageQueue上,以实现动态扩容

你可能感兴趣的:(消息中间件,kafka,分布式)