kafka消费组重平衡

kafka消费组

Consumer Group,是 Kafka 提供的可扩展且具有容错性的消费者机制,一个消费组内可以有一到多个消费实例(Consumer Instance),共享一个id,这个id就是Group ID。

  • Consumer Group下有一个或多个单独的Consumer实例,这个Consumer可以是单独的进程,也可以是一个进程下的多个线程。
  • Group ID是一个字符串,用来表示唯一的消费组。
  • Consumer Group下所有实例订阅的主题的单个分区,只能分配给组内的某个 Consumer 实例消费。这个分区当然也可以被其他的 Group 消费。
  • 在理想情况下,consumer的个数应该与订阅的主题的分区树相等。

什么是重平衡

Rebalance其实就是一种协议,用来定义Consumer Group下的所有consumer实例,如何分配对应订阅主题分区数量。在rebalance过程中,所有consumer实体共同参与,在组协调器(Coordinator)帮助下,完成订阅主题的分区分配。

组协调器(Coordinator):准备为Consumer Group服务,负责为 Group 执行 Rebalance 以及提供位移管理和组成员管理等。当consumer端提交位移时,其实就是给Coordinator所在的Broker提交位移,并且当Consumer启动时,也是向Coordinator所在的Broker发送各种请求。

查找对应组协调所在的Broker的步骤分为2步

  • 确定由位移主题的哪个分区来保存该 Group 数据

partitionId=Math.abs(groupId.hashCode() % offsetsTopicPartitionCount)

  • 找出该分区leader副本所在的Broker,这个Broker即为Coordinator

什么时候发生重平衡

  • Consumer Group中的成员有发生变化,比如新增或剔除某个consumer实体。
  • 订阅的主题数发生变化时。比如使用正则表达式订阅某些主题后,新增一个主题,就会发生rebalance。
  • 订阅主题的分区数发生变化时。kafka目前只允许新增对应的分区,当新增分区时,就会触发Group的rebalance。

rebalance的影响

  • rebalance的时候,Consumer会停止消费,等待rebalance的完成。消息ConsumerTPS。
  • rebalance效率不高,需要消费组下的所有消费者都参与其中,重新进行分区的分配,那么原本consumer1连接的partition1,partition2,rebalance后可能变成消费partition3,partition4的消息,这个时候有需要与新的broker进行TCP连接,浪费资源。
  • 会造成重复消费,当Consumer消费了一个数据还没来及其提交消费位移时,发生了rebalance,这个分区被分配给了另一个consumer,那么原本消费完的数据又会重新被消费一遍。

consumer消费的分区策略

RangeAssignor分配策略

每个主题的分区总数除了消费者总数得到一个跨度,然后根据这个跨度进行平均分配,当不够平均分配时,字典序考前的消费者会被多分配一个分区。

例如有两个消费者C0,C1都订阅了主题t0和t1,并且t0和t1有4个分区,那么按照RangeAssignor的分配策略

C0:t0p0、t0p1、t1p0、t1p1
C1:t0p2、t0p3、t1p2、t1p3

假设有两个消费者C0,C1都订阅了主题t0和t1,主题有3个分区,那么按照RangeAssignor的分配策略

C0:t0p0、t0p1、t1p0、t1p1
C1:t0p2、t1p2

当每个主题的分区数无法平均分配时,前面的消费者总会多分配到partition,导致消费者分配不均。

RoundRobinAssignor分配策略

将消费者订阅的主题的分区总数,进行轮询的方式分配给消费者。但是当消费组内消费者订阅的信息不一致时,这个时候就会出现消费倾斜的问题。

假设有两个消费者C0,C1都订阅了主题t0和t1,主题有3个分区,那么按照RoundRobinAssignor的分配策略

C0:t0p0、t0p2、t1p1
C1:t0p1、t1p0、t1p2

某个消费组下有3个消费者实例,订阅的t0、t1、t2三个分区,具体的分区数如下(t0p0、t1p0、t1p1、t2p0、t2p1、t2p2),消费者C0只订阅了主题t0、消费者C1定于了主题t0和t1,消费者C2订阅了t0、t1、t2,那么最终的分配结果

C0:t0p0
C1:t1p0
C2:t1p1、t2p0、t2p1、t2p2

当消费组内的每个消费者订阅的主题不相同时,会导致消费倾斜。

StickyAssignor分配策略

sticky表示黏性的,自kakfa0.11.x版本引入,使用这个策略主要有两个目的,当两者发生冲突时,第一目标优先于第二目标

  1. 分区的分配要尽可能均匀。
  2. 分区的分配尽可能与上次分配的保持相同。

假设某个消费组有3个消费者(C0、C1、C2),都订阅了4个主题(t0、t1、t2、t3),每个主题有2个分区,那么最终的分配结果如下:

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

这个分配策略,初次分配感觉和RoundRobinAssignor分配策略的结果相同,真正不同的时候,是在发生rebalance时,例如消费者C1脱离了消费组rebalance之后的分配结果如下:

  • RoundRobinAssignor分配策略,会进行完全的重新在分配

C0:t0p0、t1p0、t2p0、t3p0
C2:t0p1、t1p1、t2p1、t3p1

  • StickyAssignor分配策略,按照上述第二个条件,会尽量保持与上次分配的相同

C0:t0p0、t1p1、t3p0、t2p0
C2:t1p0、t2p1、t0p1、t3p1

如何避免不必要的rebalance

发生rebalance的三个条件中,后面两个条件基本都是运维操作过程中,可能必须要执行的,这个无法避免,最主要的就是避免减少Consumer被Coordinator 错误地认为“已停止”从而被“踢出”Group而发生rebalance。主要因素有2个

  • consumer未发送心跳到Coordinator:每个consumer实例需要定期发送心跳给Coordinator,当Coordinator在规定的时间内没有收到某个consumer实体的心跳请求,就被认为consumer实体下线了,从而发生rebalance。这个时间间隔,由参数session.timeout.ms约定,默认值为10秒。还有一个参数用来控制心跳请求发送的频率,其配置项为heartbeat.interval.ms,这个值设置的过小,会导致频繁的发送心跳请求,占用资源带宽;好处是可以更快的开启rebalance,因为 Coordinator 通知各个 Consumer 实例开启 Rebalance 的方法,就是将 REBALANCE_NEEDED 标志封装进心跳请求的响应体中。
  • consumer消费时间过长:max.poll.interval.ms。表示consumer两次poll的最大间隔时间,默认值为5分钟;如果Consumer 程序如果在 5 分钟之内无法消费完 poll 方法返回的消息,那么 Consumer 会主动发起“离开组”的请求,Coordinator 也会开启新一轮 Rebalance。

如何进行避免rebalance呢?

  • 合理设置参数

session.timeout.ms = 6s
heartbeat.interval.ms = 2s
保证 Consumer 实例在被判定为“dead”之前,能够发送至少 3 轮的心跳请求,即 session.timeout.ms >= 3 * heartbeat.interval.ms

  • 加快consumer实例消费速度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值