Kafka中再均衡的发生过程

376 阅读4分钟

Kafka中再均衡的发生过程

Kafka中消费者以消费组的形式存在,消费组来消费每个主题中分区的数据,因为主题中的分区数和消费者数量并不一一对应,这时候就涉及到如何为每个消费者分配分区,而当有消费者在中途退出时,就会触发再均衡的发生,再重新为剩余的消费者分配分区。每个消费组在服务端对应一个GroupCoordinator对其进行管理,而消费者客户端中的ConsumerCoordinator组件负责与GroupCoordinator进行交互,它们负责执行分区的分配,以及消费者再均衡的操作。

目前在以下几种情况会触发再均衡操作。

  1. 有新的消费者加入消费组。
  2. 消费者宕机下线。消费者并不一定需要真正下线,例如遇到长时间的GC、网络延迟等情况,导致消费者长时间未向GroupCoordinator 发送心跳,GroupCoordinator认为消费者已经下线。
  3. 有消费者主动退出消费组。
  4. 消费组所对应的GroupCoorinator 节点发生了变更。
  5. 消费组内所订阅的任一主题或者主题的分区数量发生变化。

在服务刚启动时,需要确立消费者协调器和消费组协调器,并根据已有的分区规则进行分配。

1.查找GroupCoordinator

消费者需要连接它所属的GroupCoordinator所在broker,如果没有保存对应GroupCoordinator节点信息,则像集群中负载最小的节点发送请求来查找,Kafka通过计算可以在__consumer_offsets找到此分区对应的leader副本所在的节点,这个broker节点就是GroupCoordinator节点,让此broker节点即扮演GroupCoordinator节又扮演保存分区分配方案和组内消费者位移的角色,可以省去很多不必要的中间轮转所带来的开销。

2.加入GroupCoordinator

在得知GroupCoordinator节点位置后,消费者便发送加入请求,GroupCoordinator节点会选举消费组的leader,消费组leader会负责之后具体分区分配策略。由于各个客户端的分区策略都可以自定义配置,这时还要进行投票选举,Kafka主要有以下几种分区策略。
  • RangeAssignor分配策略:按照消费者总数和分区总数进行整除运算来获得一个跨度,然后将分区按照跨度进行平均分配,以保证分区尽可能均匀地分配给所有的消费者。
  • RoundRobinAssignor分配策略:将消费组内所有消费者及消费者订阅的所有主题的分区按照字典序排序,然后通过轮询方式逐个将分区依次分配给每个消费者。
  • StickyAssignor分配策略:Sticky翻译为黏性的,主要保证分区的分配要尽可能均匀,分区的分配尽可能与上次分配的保持相同,

StickyAssignor要比前两种策略更加复杂,它的优势是,当再均衡发生,不需要将所有消费者已经分配好的分区,再重新打乱分配一边,尽量保证与上一次结果相似。Kafka也支持自定义分区分配策略,根据业务需要来进行加权或其他方面的考虑,甚至还可以打破Kafka默认消费逻辑,不必局限于一个分区只能被同一个消费组内的一个消费者消费。

3.正常工作阶段

当消费组的leader通过GroupCoordinator将分区分配方案同步到各个消费者之后,消费者确定好拉取消息的起始位置,开始正常工作,消费者通过向GroupCoordinator发送心跳来维持它们与消费组关系,在正常时间间隔内发送心跳就是活跃的,发送心跳是一个独立的线程,也可以在轮询消息的空档发送心跳。
消费者的心跳间隔时间由参数heartbeat.interval.ms指定,超过一定时间未发送心跳,就会被认为已经死亡。
如果消费者发生崩溃,并停止读取消息,那么GroupCoordinator会等待一小段时间,确认这个消费者死亡之后才会触发再均衡。这个一小段时间由session.timeout.ms参数控制。
GroupCoordinator还会判断消费者调用poll()的时间期限,如果超过参数max.poll.interval.ms设定的值,则消费者被视为失败,并且分组将重新平衡,以便将分区重新分配给别的成员。

最后,除了异常被动退出消费组,也可以调用LeaveGroupRequest请求主动退出消费者,或者使用unsubscrible方法取消对某些主题的订阅,都可以触发再均衡。