消息队列MQ

kafka(三)重平衡

本文主要是介绍kafka(三)重平衡,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

历史文章:

kafka(一)kafka的基础与常用配置

文章目录

  • 一、kafka消费者组
  • 二、重平衡(Rebalance)
    • 2.1、重平衡触发条件
    • 2.2、重平衡策略
      • 2.2.1、Range 平均分配
      • 2.2.2、RoundRobin 轮询分配
      • 2.2.3、Sticky 粘性分配
    • 2.3、重平衡过程
      • 2.3.1、消费者组状态
      • 2.3.2重平衡过程
    • 2.4、避免重平衡

一、kafka消费者组

由消费者组成的存在一个或多个消费者实例成为消费者组,这些消费者实例共享一个igroup id。

消费者组内的所有成员一起订阅某个主题的所有分区,每个分区只能由消费者组内的其中一消费者订阅。
下图是kakfa官网上给出的说明:
在这里插入图片描述

可以看到消费者组中的消费者会消费不同分区,当消费者组中的消费者数量发生变化时,这时候就会触发kafka中的rebalance

二、重平衡(Rebalance)

2.1、重平衡触发条件

重平衡的触发条件有三个:

  • 消费者组内成员发生变更:比如组内有机器崩溃离场,或者是添加新的机器入组。
  • 订阅主题数量发生变化:kafka目前只支持增加分区。
  • 订阅主题的分区数发生变化。

在重平衡的过程中,**消费者将无法从分区中消费消息,因为此时需要重新分配分区给组内的消费者。**如果kafka集群内有很多节点,那么重平衡可能导致严重的性能问题,在重新分配分区的阶段,kafka基本上处于不可用状态。所以在实际环境中,应该尽量避免重平衡发生。

2.2、重平衡策略

kafka中有三种重平衡策略

2.2.1、Range 平均分配

组内的消费者会基于topic平均分配topic中的分区。如果主题中的分区分区不能平均分配给组内每个消费者,那么某个消费者会分配到额外的分区。
假如目前有两个消费者1和消费者2,topicA中有三个分区t1,t2,t3,topicB中有三个分区a1,a2,a3。
rebalance后的结果:

  • 消费者1:t1, t2,a1,a2
  • 消费者2:t3,a3

2.2.2、RoundRobin 轮询分配

RoundRobin是基于全部主题的分区来进行分配的,这是是kafka默认的rebalance分区策略。还是用刚刚的例子来看,
举假如目前有两个消费者1和消费者2,topicA中有三个分区t1,t2,t3,topicB中有三个分区a1,a2,a3。
rebalance后的结果:

  • 消费者1:t1, t2, 12
  • 消费者2:t3, a1, a2
    可以看到轮询策略可以更加均衡的分配分区给到消费者。

2.2.3、Sticky 粘性分配

Sticky分配策略是最新的也是最复杂的策略,其具体实现位于package org.apache.kafka.clients.consumer.StickyAssignor。
这种分配策略是在0.11.0才被提出来的,主要是为了一定程度解决上面提到的重平衡非要重新分配全部分区的问题。称为粘性分配策略。
听名字就知道,主要是为了让目前的分配尽可能保持不变,只挪动尽可能少的分区来实现重平衡。
还是举例说明,有三个消费者C0,C1,C2 。三个主题t0,t1,t2,t3。每个主题各有两个分区, t0p0,t0p1,t1p0,t1p1,t2p0,t2p1,t3p0,t3p1。
现在订阅情况如下:

  • C0:t0p0,t1p1,t3p0
  • C1:t0p1,t2p0,t3p1
  • C2:t1p0,t2p1

假设现在C1挂掉了,如果是RoundRobin分配策略,那么会变成下面这样:

  • C0:t0p0,t1p0,t2p0,t3p0
  • C2:t0p1,t1p1,t2p1,t3p1

就是说它会全部重新打乱,再分配,而如何使用Sticky分配策略,会变成这样:

  • C0:t0p0,t1p1,t3p0,t2p0
  • C2:t1p0,t2p1,t0p1,t3p1
    也就是说,尽可能保留了原来的分区情况,不去改变它,在这个基础上进行均衡分配,不过这个策略目前似乎还有些bug,所以实际使用也不多。

2.3、重平衡过程

2.3.1、消费者组状态

Kafka 为消费者组定义了 5 种状态,它们分别是:

  1. Empty:组内无成员,但是存在未过期的已提交数据。
  2. Dead:组内无成员,数据被删除。
  3. PreparingRebalance:准备开始重平衡,所有成员都需要重新请求加入组。
  4. CompletingRebalance:所有成员都已经加入,等待分配方案。
  5. Stable:重平衡完成,组内消费者可以正常开始消费。
    状态机:

2.3.2重平衡过程

消费者会向协调者发送两个请求:
JoinGroup:申请加入消费者组
SyncGroup:分配方订阅案

消费者在申请加入消费者组的时候,会向协调者发送JoinGroup请求,协调者收到请求后会选择一个消费者担任领导者。通常情况下,第一个发送的成员会自动成为领导者。这里的领导者主要作用是收集所有消费者的信息并制定分配方案。

领导者完成方案分配后,会通过SyncGroup命令,将分配方案发给协调者。其他消费者也会向协调者发送SyncGroup命令,请求不包含任何信息,返回会携带当前消费者的分配信息,包含哪个分区等。

以下几个场景会触发重平衡:

  1. 新成员入组。
  2. 组内成员主动离组。
  3. 组内成员崩溃离组。

重平衡会导致一定程度的阻塞,导致消费者处于不可用状态。

2.4、避免重平衡

要说完全避免重平衡,那是不可能的,因为你无法完全保证消费者不会故障。而消费者故障其实也是最常见的引发重平衡的地方,所以要尽量避免重平衡。

在实际场景中,有部分情况会让kafka错误地认为一个正常的消费者已经挂掉了,我们需要避免这样的情况出现。

为什么会出现这种情况?
在分布式系统中,通常是通过心跳来维持分布式系统的,某些场景由于网络问题没接收到心跳,导致kafka认为消费者挂了,而重新开始重平衡。kafka提供了一个参数:session.timout.ms 。这个参数是用来判断多少时间内没有心跳请求的消费者,我们认为他是真正挂了。

另一个参数:heartbeat.interval.ms。这个参数控制发送心跳的频率,频率越高越不容易被误判,当然也会消耗更多的cpu资源。

这篇关于kafka(三)重平衡的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!