负载均衡
每个 Consumer Group 可以包含多个消费实例,即可以启动多个 Kafka Consumer,并把参数 GroupID 设置成相同的值。属于同一个 Consumer Group 的消费实例会负载消费订阅的 Topic。
举例:Consumer Group A 订阅了 Topic A,并开启三个消费实例 C1、C2、C3,则发送到 Topic A 的每条消息最终只会传给 C1、C2、C3 的某一个。Kafka 默认会均匀地把消息传给各个消息实例,以做到消费负载均衡。
Kafka 负载消费的内部原理是,把订阅的 Topic 的分区,平均分配给各个消费实例。因此,消费实例的个数不要大于分区的数量,否则会有实例分配不到任何分区而处于空跑状态。这个负载均衡发生的时间,除了第一次启动上线之外,后续消费实例发生重启、增加、减少等变更时,都会触发一次负载均衡。
消息队列 Kafka 的每个 Topic 的分区数量默认是 16 个,已经足够满足大部分场景的需求,且云上服务会根据容量调整分区数。
分区
主题的分区数有多少个,这个主题的数据就会被分成多少份。这个分区数最好就是消费者数的整数倍。
如果分区数小于消费者数,前面的消费者会分到一个分区的数据消费,后面超过分区数的消费者将无消费消费,除非前面的消费者宕机了。如果分区数大于消费者数,每个消费者至少分配到一个分区的数据,两个消费者间分区数相差不超过一,如果有新的消费者加入,会把那些分区数多的消费者分区,分配给新的消费者。
比如:分区数可以设置成 6、12 等数值。比如 6,当消费者只有一个时,这 6 个分区都归这个消费者,后面再加入一个消费者时,每个消费者都负责 3 个分区,后面再加入一个消费者时,每个消费者就负责 2 个分区。每个消费者分配到的分区数是一样的,可以均匀地消费。另外同一个分区写入是有顺序的,如果要保证全局有序,那只能设置一个分区。如果要消费者也有序,消费者也只能有一个。
多个组订阅
一个 Consumer Group 可以订阅多个 Topic。一个 Topic 也可以被多个 Consumer Group 订阅,且各个 Consumer Group 独立消费 Topic 下的所有消息。
举例:Consumer Group A 订阅了 Topic A,Consumer Group B 也订阅了 Topic A,则发送到 Topic A 的每条消息,不仅会传一份给 Consumer Group A 的消费实例,也会传一份给 Consumer Group B 的消费实例,且这两个过程相互独立,相互没有任何影响。
提高消费速度
增加 Consumer 实例个数。「超过分区数就不行了」
消费阻塞以及堆积
消费端最常见的问题就是消费堆积,最常造成堆积的原因是:
(1)消费速度跟不上生产速度,此时应该提高消费速度
(2)消费端产生了阻塞。
消费端拿到消息后,执行消费逻辑,通常会执行一些远程调用,如果这个时候同步等待结果,则有可能造成一直等待,消费进程无法向前推进。
消费端应该竭力避免堵塞消费线程,如果存在等待调用结果的情况,建议设置等待的超时时间,超时后按照消费失败处理。
消息广播
Kafka 自身没有消息广播的语义,可以通过创建不同的 Consumer Group 来模拟实现。
一条消息如何知道要被发送到哪个分区?
按照 key 值分配
默认情况下,Kafka 根据传递消息的 key 来进行分区的分配,即hash(key) % numPartitions:
这保证了相同 key 的消息一定会被路由到相同的分区。key 为 null 时,从缓存中取分区id 或者随机取一个。
如果你没有指定 key,那么Kafka是如何确定这条消息去往哪个分区的呢?
不指定 key 时,Kafka 几乎就是随机找一个分区发送无key 的消息,然后把这个分区号加入到缓存中以备后面直接使用——当然了,Kafka 本身也会清空该缓存(默认每10分钟或每次请求topic元数据时)。
文献: