1. 首页
  2. 大数据
  3. Kafka教程

Kafka大名鼎鼎又臭名昭著的消费组和重平衡

摘要:Consumer Group指多个消费者实例组成一个组来共同消费一组主题,它可谓大名鼎鼎,不仅可以加速消费端TPS,还具有扩展性和容错性等优势。而组成员之间如何达成一致来分配订阅Topic,又成为了Rebalance(重平衡)的重头大戏,不得不夸赞Rebalance在均衡和协调方面的丰功伟绩,但是它同样臭名昭著,带来了非常多让人恶心的影响,因此我们必须学会避免它。本文主要从以下几个方面来讲述消费组和重平衡的那些事:

  • Consumer Group的概念剖析和意义
  • Consumer Group的位移管理
  • Rebalance的概览剖析、优势和劣势
  • Rebalance的触发场景,如何避免

Consumer Group概念剖析

什么是消费组

如果有1000个面包,让一个人解决,他需要至少一年的时间,而让1000个人解决,只需要一分钟的时间。同理,100000条消息如果你只让一个消费者来消费,可能需要一个小时,而如果你让50个消费者来消费,只需要5分钟。这50个消费者实例组成的集合就是消费组。

你编写消费者程序的时候,如果没有指定消费组,即group.id,那么程序是无法运行的,会抛出以下异常:

org.apache.kafka.common.errors.InvalidGroupIdException。

所以可以看出Consumer Group是kafka消费的标配,消费者组,指的是多个消费者实例组成一个组来消费一组主题。

消费组的意义

为什么要有它的存在呢?首先根据面包那个例子,很容易得出是为了效率问题,多个消费者实例同时消费,加速整个消费端的吞吐量(TPS)。当然它的作用不仅仅是瓜分订阅主题的数据,加速消费。它们还能彼此协助。假设组内某个实例挂掉了,Kafka 能够自动检测到,然后把这个 Failed 实例之前负责的分区转移给其他活着的消费者,这个过程称之为重平衡(Rebalance),因此也可以得出Consumer Group 是 Kafka 提供的可扩展且具有容错性的消费者机制。

关于ConsumerGroup,比较简单,只需要记住以下几个重要的点就可以了:

1、一个分区只能被消费者组中的其中一个消费者去消费,组员之间不能重复消费

2、Consumer Group 下可以有一个或多个 Consumer 实例。这里的实例可以是一个单独的进程,也可以是同一进程下的线程。在实际场景中,使用进程更为常见一些。

如何设计消费组

在了解了 Consumer Group 以及它的设计亮点之后,你可能会有这样的疑问:在实际使用场景中,我怎么知道一个 Group 下该有多少个 Consumer 实例呢?理想情况下,Consumer 实例的数量应该等于该 Group 订阅主题的分区总数。

这个答案是不难得出的,因为刚刚我说了你必须记住的一个特性是一个分区只能被消费者组中的其中一个消费实例去消费。如果你有100个分区,200个消费者组成一个消费组,由于1个消费者只能消费1个分区的数据,那么就有100个消费者没事干吃干饭了。所以一般情况下组成员数不比分区数量多,否则造成资源浪费。可以少于分区数,比如只有2个消费者,那么它们会均摊这100个分区进行消费。但如果时效性要求较高的场景,最好保持一致,这样可以提高吞吐量。千万不要只给一个消费者,这样一旦它挂了,消费就等于停止了,不符合可用性要求。

位移管理

关于位移管理,在kafka消费位移那些事已经作了详细说明,如果不清楚希望你再去看一遍Kafka消费位移的那些事 。这里只是想展示一下消费组消费进度查看的命令,通过这个命令,你可以知道当前消费组消费了哪些topic,每个分区的消费进度如何,以及每个分区是由哪个消费者进行消费的。从下面的信息也可以得出,一个分区只会被一个消费者消费。

查看消费组消费进度

bin/kafka-consumer-groups.sh –bootstrap-server localhost:9092 –describe –group test

TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
kafka_test 2 7290 7292 2 consumer-3-7edccfc6-ab05-4871-b1ea-ad06ed5038c1 /192.168.109.1 consumer-3
kafka_test 1 7258 7258 0 consumer-2-50840b10-5550-4b9e-a357-f3667520af08 /192.168.109.1 consumer-2
kafka_test 3 7437 7437 0 consumer-4-0a30fa36-5a3c-40b6-84b8-c3f67553b27c /192.168.109.1 consumer-4
kafka_test 0 7399 7399 0 consumer-1-696cc434-d9f0-4f95-8ac5-2202dee19d2d /192.168.109.1 consumer-1

重平衡

消费者组还是很好理解的,但是它带来的重平衡可是个比较复杂的东西了。本人初次接触重平衡是这样一个异常:

org.apache.kafka.clients.consumer.CommitFailedException: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member.

大概意思是说这个消费组已经重平衡了,分配给了其他成员。

以这个错为引言是因为它是个比较容易碰到的错,我当时会抛出这个异常的原因是,我对消息进行业务逻辑处理的时间比较久,而max.poll.interval.ms参数设置的过短,该参数限定了 Consumer 端应用程序两次调用 poll 方法的最大时间间隔,如果超时无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起“离开组”的请求,Coordinator 也会开启新一轮 Rebalance。是不是现在听起来有点绕了?那就让我们从头开始揭开重平衡的神秘面纱吧。

重平衡是什么以及引入它的意义

首先为何要有重平衡?听完我刚刚那个例子你可能会觉得这只是个坏事儿的东西,我只不过处理时间长了点你就给我抛异常!不,其实它是大名鼎鼎的,只不过它大名鼎鼎的同时也臭名昭著。

文章开头我们说到:假设组内某个实例挂掉了,Kafka 能够自动检测到,然后把这个 Failed 实例之前负责的分区转移给其他活着的消费者,这个过程称之为重平衡(Rebalance)。这无疑是非常有用的一个东西,可以保障高可用性。除此之外,它协调着消费组中的消费者分配和订阅topic分区,比如某个 Group 下有 20 个 Consumer 实例,它订阅了一个具有 100 个分区的 Topic。正常情况下,Kafka 平均会为每个 Consumer 分配 5 个分区。这个分配的过程也叫 Rebalance。再比如此刻新增了消费者,得分一些分区给它吧,这样才可以负载均衡以及利用好资源,那么这个过程也是Rebalance来完成的。

综上:Rebalance 本质上是一种协议,规定了一个 Consumer Group 下的所有 Consumer 如何达成一致,来分配订阅 Topic 的每个分区。

在 Rebalance 过程中,所有 Consumer 实例共同参与,在协调者组件(Coordinator,专门为 Consumer Group 服务,负责为 Group 执行 Rebalance 以及提供位移管理和组成员管理)的帮助下,完成订阅主题分区的分配。

现在是否对重平衡的态度180°大转弯,觉得它实在是太好了!不,现在就要开始说它臭名昭著的那些事儿了。

重平衡的劣势

第一:Rebalance 影响 Consumer 端 TPS,对 Consumer Group 消费过程有极大的影响。 我们知道JVM 的垃圾回收机制,那可怕的万物静止的收集方式,即stop the world,所有应用线程都会停止工作,整个应用程序僵在那边一动不动。类似,在 Rebalance 期间,Consumer 会停下手头的事情,什么也干不了。

第二:Rebalance 很慢。如果你的 Group 下成员很多,就一定会有这样的痛点。某真实案例:Group 下有几百个 Consumer 实例,Rebalance 一次要几个小时。万物静止几个小时是非常可怕的一件事了,老板可能要提大刀来相见了。

为什么会这么慢呢?因为目前 Rebalance 的设计是让所有 Consumer 实例共同参与,全部重新分配所有分区。其实应该尽量保持之前的分配,目前kafka社区也在对此进行优化,在0.11版本提出了StickyAssignor,即有粘性的分区分配策略。所谓的有粘性,是指每次 Rebalance 时,该策略会尽可能地保留之前的分配方案。不过不够完善,有bug,暂时不建议使用。

现在是否再次对重平衡的态度180°大转弯,觉得它实在是太坏了!可是没办法,如果你没有能力改造它,那么你只能选择了解它并且避免它。

重平衡的触发条件

既然要避免,肯定要知道 Consumer Group 何时会触发 Rebalance 呢?

  • 组成员数发生变更。比如有新的 Consumer 实例加入组或者离开组,抑或是有 Consumer 实例崩溃被“踢出”组。

  • 订阅主题数发生变更。

  • 订阅主题的分区数发生变更。

如何避免Rebalances

刚刚说到三个触发机制,后面两者一般是用户主动操作,这不可避免,所以我们应该重点关注第一个场景,当然消费实例增加也是出于伸缩性的需求,所以其实我们只需要避免实例减少的情况就行了。现在可能你会说,那还不简单,我尽量不减少实例就好了。可必须要先明白一点,不是你主动kill消费成员,或者机器宕机那种情况,才算是被踢出组,现在回去看看我开头那个例子,消费时间过长,也是会被踢的。不仅如此,某些情况会让 Coordinator 错误地认为Consumer 实例“已停止”从而被“踢出”Group。如果是这个原因导致的 Rebalance,我们就不能不管了。

那么,现在我们的侧重点已经很清晰了,我们需要归纳出哪些情景会让协调者认为消费者实例已经死亡并把他们踢出组。

1、Consumer 实例未能及时发送心跳,导致Coordinator误认为它已经死亡。心跳这东西,在大数据领域应该司空见惯,比如HBase,Hdfs都有定时发送心跳的概念,目的都是为了通知其他组件”我还活着”。在kafka的世界中,每个Consumer都会定期发送心跳给Coordinator的,表明它还存活着。那么发送心跳必然有一个阈值和频率的概念。阈值是Coordinator最长能接受的心跳间隔,默认10s,即超过10s还没收到心跳才认定consumer死亡,从而将其从 Group 中移除,然后开启新一轮 Rebalance。频率是指Consumer发送心跳的频率。它俩对应的参数分为叫做session.timeout.ms,heartbeat.interval.ms,因此你需要合理的设置这两个参数。

千万不要无脑的觉得我把频率调高点,阈值也调高点,比如我1s发一次心跳,并设置超过1分钟才可以认定为死亡,就完美避免了未能及时收到心跳请求而误认为死亡。可你别忘了,发送心跳的目的就是为了及时通知协调者自己是否健康。最近的新冠肺炎,要求我们每天上报一次健康状况,如果每小时上报一次,未免太浪费人力了,如果一周上报一次,又会带来严重后果。所以session.timeout.ms这个参数,不宜最长,毕竟,我们还是希望能尽快揪出那些“尸位素餐”的 Consumer,早日把它们踢出 Group。heartbeat.interval.ms这个值也不宜过短,频繁地发送心跳请求会额外消耗带宽资源。

推荐设置 session.timeout.ms = 6s。

推荐设置 heartbeat.interval.ms = 2s。

保证 Consumer 实例在被判定为“dead”之前,能够发送至少 3 轮的心跳请求,因此上面推荐的配置是一个三倍的关系。

2、Consumer 消费时间过长导致的。又回到开头那个场景,我初次遇到重平衡就是因为我业务逻辑复杂,Consumer 因为处理这些消息的时间太长而引发 Rebalance 了。Consumer 端有一个参数,用于控制 Consumer 实际消费能力对 Rebalance 的影响,即 max.poll.interval.ms 参数。它限定了 Consumer 端应用程序两次调用 poll 方法的最大时间间隔。它的默认值是 5 分钟,表示你的 Consumer 程序如果在 5 分钟之内无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起“离开组”的请求,Coordinator 也会开启新一轮 Rebalance。因此你最好将该参数值设置得大一点,比你的下游最大处理时间稍长一点。还可以配置一个参数max.poll.records,它代表批量消费的size,如果一次性poll的数据量过多,导致一次poll的处理无法在指定时间内完成,则会Rebalance。因此,你需要预估你的业务处理时间,并正确的设置这两个参数。

3、GC问题:按照上面的推荐数值恰当地设置了这几个参数,却发现还是出现了 不必要的Rebalance,那么可能是Consumer 端的 GC 导致的,比如是否出现了频繁的 Full GC 导致的长时间停顿,从而引发了 Rebalance。

总结

本文从消费组的概念和优势出发,带你看到了它大名鼎鼎的一方面,但由它导致的重平衡问题却是众多开发者心中的毒瘤,它为何会出现,重平衡的意义在哪,什么时候会触发、又该如何避免呢。我们一定要避免因为各种参数或逻辑不合理而导致的组成员意外离组或退出的情形,与之相关的主要参数有:
session.timeout.ms
heartbeat.interval.ms
max.poll.interval.ms
max.poll.records
GC 参数
恰当地设置这些参数,你一定能够大幅度地降低生产环境中的 Rebalance 数量,从而真正享受消费组和重平衡带来的利好。

BDStar原创文章。发布者:Liuyanling,转载请注明出处:http://bigdata-star.com/archives/2273

发表评论

登录后才能评论

联系我们

562373081

在线咨询:点击这里给我发消息

邮件:562373081@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code