概念

  1. Rebalance是让Consumer Group下所有的Consumer实例就如何消费订阅主题的所有分区达成共识的过程
  2. 在Rebalance过程中,所有Consumer实例共同参与,在协调者组件的帮助下,完成订阅主题分区的分配
  3. 整个Rebalance过程中,所有Consumer实例都不能消费任何消息,因此对Consumer的TPS影响很大

协调者

  1. 协调者,即Coordinator,负责为Consumer Group执行Rebalance以及提供位移管理组成员管理
  2. Consumer端应用程序在提交位移时,其实是向Coordinator所在的Broker提交位移
  3. Consumer应用启动时,也是向Coordinator所在的Broker发送各种请求
    • 然后由Coordinator负责执行消费组的注册成员管理记录元数据管理操作
  4. 所有Broker在启动时,都会创建和开启相应的Coordinator组件,所有Broker都有各自的Coordinator组件
  5. 内部位移主题__consumer_offsets记录了为Consumer Group服务的Coordinator在哪一台Broker上
  6. 为某个Consumer Group确定Coordinator所在的Broker,有两个步骤
    • 确定由位移主题的哪个分区来保存该Consumer Group数据
      • partitionId = Math.abs(groupId.hashCode() % offsetsTopicPartitionCount
      • offsetsTopicPartitionCount默认为50
    • 找出该分区Leader副本所在的Broker,该Broker即为对应的Coordinator

弊端

  1. Rebalance影响Consumer端TPS
  2. Rebalance很慢
  3. Rebalance效率不高
    • 每次Rebalance,Consumer Group下所有成员都需要参与,而且不考虑局部性原理,_之前的分配方案都不会被保留_
    • 为了解决这个问题,社区于0.11.0.0版本推出StickyAssignor,即粘性的分区分配策略
      • 粘性指的是每次Rebalance,都尽可能地保留之前的分配方案,尽量实现分区分配的最小改动
      • 但该策略存在一些Bug,而且需要升级到0.11.0.0才能使用,实际生产环境中用得不多
  4. 影响Consumer端TPS + 慢属于无解,因此尽量_减少不必要的Rebalance_

发生时机

  1. 组成员数量发生变化 – 最常见
    • Consumer实例增加:一般是基于增加TPS或者提高伸缩性的需要,属于计划内的操作,不属于不必要的Rebalance
    • Consumer实例减少:在某些情况下Consumer实例会被Coordinator错误地认为已停止而被踢出Consumer Group
  2. 订阅主题数量发生变化
    • 一般是运维主动操作,很难避免
  3. 订阅主题的分区数量发生变化
    • 一般是运维主动操作,很难避免

实例减少

Consumer端参数

  1. 当Consumer Group完成Rebalance后,每个Consumer实例都会定期地向Coordinator发送心跳
  2. 如果某个Consumer实例不能及时地发送心跳
    • Coordinator会认为该Consumer已死,并将其从Consumer Group中移除,开启新一轮的Rebalance
  3. Consumer端有一个参数session.timeout.ms,默认值为10秒
    • 如果Coordinator在10秒内没有收到Consumer Group下某个Consumer实例的心跳,就会认为该Consumer已死
  4. Consumer端还有另一个参数heartbeat.interval.ms,默认值为3秒
    • 设置得越小,Consumer实例发送心跳的频率就会越高,会额外消耗带宽资源,但能更快地知道是否开启Rebalance
    • Coordinator通过将REBALANCE_NEEDED标志封装进心跳响应中,来通知Consumer实例开启Rebalance
  5. Consumer端还有另一个参数max.poll.interval.ms,默认值为5分钟
    • 该参数用于控制Consumer实际消费能力对Rebalance的影响,限定了Consumer端两次调用poll方法的最大时间间隔
    • Consumer如果在5分钟内无法消费完poll方法返回的消息,就会主动发起离开组的请求,开启新一轮的Rebalance

非必要的Rebalance

  1. Consumer未及时发送心跳,导致被踢出Consumer Group而引发的Rebalance
    • 生产配置:session.timeout.ms=6000 + heartbeat.interval.ms=2000
      • session.timeout.ms=6000:为了让Coordinator能够更快地定位已经挂掉的Consumer
    • session.timeout.ms > 3 * heartbeat.interval.ms
  2. Consumer消费时间过长,主动发起离开组的请求而引发的Rebalance
    • 如果消费逻辑很重(如DB操作),可以将max.poll.interval.ms设置得大一点
  3. 关注Consumer端的GC表现,频繁的Full GC会引起非预期的Rebalance

参考资料

Kafka核心技术与实战