kafka —— 消费者组与重平衡机制

概念

kafka由Producer(生产者)、Topic(主题)、Consumer(消费者)三部分组成。
消费组id(group id)相同的消费者,组成一个消费者组。
kafka的设计理念就是在消息队列的基础上优化产生的,首先了解一下什么是消息队列。

消息队列

刚接触消息队列的时候,是在后端中的activeMQ消息中间件,后来了解到消息队列分点对点和发布订阅俩种:

1、点对点:

在这里插入图片描述
如图,Producer 1(生产者)发送一条消息到queue,只有一个Consumer 1(消费者)能收到。消费者接收消息,并删除队列中数据,消息只能被消费一次。这种模型有一个问题,那就是只能由一个消费者消费,无法让多个消费者消费数据(不做其他处理的话)。所以后面演化出发布-订阅。

2、发布-订阅模型:

在这里插入图片描述
(上图英文不对)Publisher(发布者)发送消息到topic,订阅了topic的Subscriber(订阅者)才会收到消息。这就解决了上面一个消费者的限制。

kafka的消费者组机制,可以同时实现这两种模型。

消费者组(Consumer group)

默认消费者的group id是在KAFKA_HOME/conf/consumer.properties中定义,默认的group id是test-consumer-group。

消费者组内的所有成员一起订阅某个主题的所有分区,注意一个消费者组中,每一个分区只能由组内的一消费者订阅。
在这里插入图片描述
图中表示的很清楚了,2个brokerserver,4个partition,2个消费者组A和B,A中有2个消费者,B中有4个消费者,A中2对4每个消费者消费俩个分区,B中4对4每个消费者消费1个分区。
此图能直观的表达出的概念
1、如果分区和消费者组内消费者成比例关系,那么消费者会平均消费topic的分区数据
所以,消费者组内的消费者数量最好是与分区数持平,或者分区数的数量成比例。
未表达出的概念
1、如果消费者多于分区,会如何?
2、如果分区多于消费者,且不成比例会如何?
结果是
1、如果消费者多于分区,那么就会导致多余的消费者空闲,浪费资源
2、这个就要看情况了,可能会有空闲的消费者,也可能会导致多个消费者消费不同数量的分区,就是我接下来要说的冲平衡机制

重平衡(Rebalance)

重平衡是kafka内很重要的一个点,因为很多项目需要借此设计代码并行度,设计不好重启后还会导致其他问题。
重平衡是一个协议,它规定了如何让消费者组下的所有消费者来分配topic中的每一个分区。

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

  1. 消费者组内消费者增加或者减少
  2. 分区数发生变更,kafka目前只支持增加分区
  3. 订阅的主题发生变化,例如:消费者组使用正则表达式订阅主题,而恰好又新建了对应的主题

重平衡过程中,消费者无法从kafka消费消息,这对kafka的TPS影响极大,而如果kafka集内节点较多,比如数百个,那重平衡可能会耗时极多。数分钟到数小时都有可能,而这段时间kafka基本处于不可用状态。所以在实际环境中,应该尽量避免重平衡发生。

重平衡的三种策略:
1、RoundRobin

具体实现位于,package org.apache.kafka.clients.consumer.RoundRobinAssignor。

RoundRobin是基于全部主题的分区来进行分配的,同时这种分配也是kafka默认的rebalance分区策略。还是用刚刚的例子来看,

举例:两个消费者C0和C1,两个主题t0和t1,每个主题三个分区,分别是t0p0,t0p1,t0p2,和t1p0,t1p1,t1p2。

由于是基于全部主题的分区,那么分配情况会是 6/2=3

C0:t0p0, t0p1, t1p1
C1:t1p0, t0p2, t1p2
1人3个

因为是基于全部主题的分区来平均分配给消费者,所以这种分配策略能更加均衡得分配分区给每一个消费者。

上面说的都是同一消费者组内消费组都订阅相同主题的情况。更复杂的情况是,同一组内的消费者订阅不同的主题,那么任然可能会导致分区不均衡的情况。

还是举例说明,有三个消费者C0,C1,C2 。三个主题t0,t1,t2,分别有1,2,3个分区 t0p0,t1p0,t1p1,t2p0,t2p1,t2p2。

其中,C0订阅t0,C1订阅t0,t1。C2订阅t0,t1,t2。最终订阅情况如下:

C0:t0p0
C1:t1p0
C2:t1p1,t2p0,t2p1,t2p2
这个结果乍一看有点迷,其实可以这样理解,按照序号顺序进行循环分配,t0只有一个分区,先碰到C0就分配给它了。t1有两个分区,被C1和C2订阅,那么会循环将两个分区分配出去,最后到t2,有三个分区,却只有C2订阅,那么就将三个分区分配给C2。

2、Range
具体实现位于,package org.apache.kafka.clients.consumer.RangeAssignor。

这种分配是基于每个主题的分区分配,如果主题的分区分区不能平均分配给组内每个消费者,那么对该主题,某些消费者会被分配到额外的分区。我们来看看具体的例子。

举例:目前有两个消费者C0和C1,两个主题t0和t1,每个主题三个分区,分别是t0p0,t0p1,t0p2,和t1p0,t1p1,t1p2。

那么分配情况可能会是:

C0:t0p0, t0p1, t1p0, t1p1
C1:t0p2, t1p2
我来大概解释一下,range这种模式,消费者被分配的单位是基于主题的,拿上面的例子来说,是主题t0的三个分区分配给2个消费者,t1三个分区分配给消费者。于是便会出现消费者c0分配到主题t0两个分区,以及t1两个分区的情况(一个主题有三个分区,三个分区无法匹配两个消费者,势必有一个消费者分到两个分区),而非每个消费者分配两个主题各三个分区。

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,所以实际使用也不多。

避免重平衡

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

而其他几种触发重平衡的方式,增加分区,或是增加订阅的主题,抑或是增加消费者,更多的是主动控制,这里也不多讨论。

首先要知道,如果消费者真正挂掉了,那我们是没有什么办法的,但实际中,会有一些情况,会让kafka错误地认为一个正常的消费者已经挂掉了,我们要的就是避免这样的情况出现。

当然要避免,那首先要知道哪些情况会出现错误判断挂掉的情况。在分布式系统中,通常是通过心跳来维持分布式系统的,kafka也不例外。这里要说的是,在分布式系统中,由于网络问题你不清楚没接收到心跳,是因为对方真正挂了还是只是因为负载过重没来得及发生心跳或是网络堵塞。所以一般会约定一个时间,超时即判定对方挂了。而在kafka消费者场景中,session.timout.ms参数就是规定这个超时时间是多少。

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

此外,还有最后一个参数,max.poll.interval.ms,我们都知道消费者poll数据后,需要一些处理,再进行拉取。如果两次拉取时间间隔超过这个参数设置的值,那么消费者就会被踢出消费者组。也就是说,拉取,然后处理,这个处理的时间不能超过max.poll.interval.ms这个参数的值。这个参数的默认值是5分钟,而如果消费者接收到数据后会执行耗时的操作,则应该将其设置得大一些。

此篇文章关于例子方面直接借鉴他处。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值