组同步,是指当所有成员都成功加入组之后,Coordinator 指定其中一个成员为 Leader,然后将订阅分区信息发给 Leader 成员。接着,所有成员(包括 Leader 成员)向 Coordinator 发送 SyncGroupRequest 请求。需要注意的是,只有 Leader 成员发送的请求中包含了订阅分区消费分配方案,在其他成员发送的请求中,这部分的内容为空。当 Coordinator 接收到分配方案后,会通过向成员发送响应的方式,通知各个成员要消费哪些分区。
在 GroupCoordinator 类中,负责处理这个请求的入口方法就是 handleSyncGroup。它进一步调用 doSyncGroup 方法完成组同步的逻辑。后者除了给成员下发分配方案之外,还需要在元数据缓存中注册组消息,以及把组状态变更为 Stable。一旦完成了组同步操作,Rebalance 宣告结束,消费者组开始正常工作。
下面介绍handleSyncGroup方法。
def handleSyncGroup(groupId: String, // 消费者组名
generation: Int, // 消费者组Generation号,每当有新的 Rebalance 开启时,Generation 都会自动加 1。
memberId: String, // 消费者组成员ID
groupInstanceId: Option[String], // 静态成员Instance ID
groupAssignment: Map[String, Array[Byte]], // 按照成员分组的分配方案,只有 Leader 成员发送的 SyncGroupRequest 请求,才包含这个方案
responseCallback: SyncCallback): Unit = { // 回调函数
// 验证消费者状态及合法性
validateGroupStatus(groupId, ApiKeys.SYNC_GROUP) match {
// 如果未通过合法性检查,且错误原因是Coordinator正在加载,意味着本次 Rebalance 的所有状态都丢失了
// 那么,封装REBALANCE_IN_PROGRESS异常,并调用回调函数返回,让消费者组重新从加入组开始
case Some(error) if error == Errors.COORDINATOR_LOAD_IN_PROGRESS =>
// The coordinator is loading, which means we've lost the state of the active rebalance and the
// group will need to start over at JoinGroup.