Kafka GroupCoordinator机制(六):GroupMetadataManager之syncGroupGroupRequest处理

ConsumerGroup中的leader消费者会通过syncGroupRequest将分区的分配结果发送给GroupCoordinator,GroupCoordinator会根据这个分配结果形成SyncGroupResponse返回给所有的消费者。消费者受到解析后得到分区的分配结果。prepareStoreGroup()方法实现了根据分区分配结果创建消息消息的功能。

def prepareStoreGroup(group: GroupMetadata,
                    groupAssignment: Map[String, Array[Byte]],
                    responseCallback: Short => Unit): DelayedStore = {
    // 获取对应offsets topic Partition使用消息版本格式
    val (magicValue, timestamp) = getMessageFormatVersionAndTimestamp(partitionFor(group.groupId))
    // 创建记录GroupMetadata信息的消息,消息的value是分区的分配结果
    val message = new Message(
      key = GroupMetadataManager.groupMetadataKey(group.groupId),
      bytes = GroupMetadataManager.groupMetadataValue(group, groupAssignment),
      timestamp = timestamp,
      magicValue = magicValue)
    // 获取consumer Group对应的__CONSUMER_OFFSETS分区
    val groupMetadataPartition = new TopicPartition(TopicConstants.GROUP_METADATA_TOPIC_NAME, partitionFor(group.groupId))
    // __CONSUMER_OFFSET分区和消息集合的对应关系
    val groupMetadataMessageSet = Map(groupMetadataPartition ->
      new ByteBufferMessageSet(config.offsetsTopicCompressionCodec, message))

    val generationId = group.generationId

    // set the callback function to insert the created group into cache after log append completed
    // Callback会在上述消息成功追加到__CONSUMER_OFFSET中之后被调用
    def putCacheCallback(responseStatus: Map[TopicPartition, PartitionResponse]) {
      // the append response should only contain the topics partition
      if (responseStatus.size != 1 || ! responseStatus.contains(groupMetadataPartition))
        throw new IllegalStateException("Append status %s should only have one partition %s"
          .format(responseStatus, groupMetadataPartition))

      // construct the error status in the propagated assignment response
      // in the cache
      // 根据消息追加结果更新错误码
      val status = responseStatus(groupMetadataPartition)

      var responseCode = Errors.NONE.code
      if (status.errorCode != Errors.NONE.code) {
        debug("Metadata from group %s with generation %d failed when appending to log due to %s"
          .format(group.groupId, generationId, Errors.forCode(status.errorCode).exceptionName))

        // transform the log append error code to the corresponding the commit status error code
        responseCode = if (status.errorCode == Errors.UNKNOWN_TOPIC_OR_PARTITION.code) {
          Errors.GROUP_COORDINATOR_NOT_AVAILABLE.code
        } else if (status.errorCode == Errors.NOT_LEADER_FOR_PARTITION.code) {
          Errors.NOT_COORDINATOR_FOR_GROUP.code
        } else if (status.errorCode == Errors.REQUEST_TIMED_OUT.code) {
          Errors.REBALANCE_IN_PROGRESS.code
        } else if (status.errorCode == Errors.MESSAGE_TOO_LARGE.code
          || status.errorCode == Errors.RECORD_LIST_TOO_LARGE.code
          || status.errorCode == Errors.INVALID_FETCH_SIZE.code) {

          error("Appending metadata message for group %s generation %d failed due to %s, returning UNKNOWN error code to the client"
            .format(group.groupId, generationId, Errors.forCode(status.errorCode).exceptionName))

          Errors.UNKNOWN.code
        } else {
          error("Appending metadata message for group %s generation %d failed due to unexpected error: %s"
            .format(group.groupId, generationId, status.errorCode))

          status.errorCode
        }
      }

      responseCallback(responseCode)
    }

    DelayedStore(groupMetadataMessageSet, putCacheCallback)
}

prepareStoreGroup并没有追加消息的代码,它仅仅是创建了DelayedStore对象,其中封装了消息和回调函数。真正实现追加消息操作的是GroupMetadataManager.store()方法,会调用ReplicaManager.appendMessages()方法追加消息,appendMessages中的参数,第二个参数是requiredAcks,默认是-1,即isr中所有副本已经同步了才认为消息成功追加并返回。第三个参数是internalTopicsAllowed,是true,表示可以向kafka内部topic追加消息。
 

  def store(delayedAppend: DelayedStore) {
    // call replica manager to append the group message
    replicaManager.appendMessages(
      config.offsetCommitTimeoutMs.toLong,
      config.offsetCommitRequiredAcks,
      true, // allow appending to internal offset topic
      delayedAppend.messageSet,
      delayedAppend.callback)
  }

prepareStoreGroup中传入了回调函数

delayedGroupStore = Some(groupManager.prepareStoreGroup(group, assignment, (errorCode: Short) => {
    group synchronized {
      // another member may have joined the group while we were awaiting this callback,
      // so we must ensure we are still in the AwaitingSync state and the same generation
      // when it gets invoked. if we have transitioned to another state, then do nothing
      // 检测Consumer Group状态和年代信息
      if (group.is(AwaitingSync) && generationId == group.generationId) {
        if (errorCode != Errors.NONE.code) {
          resetAndPropagateAssignmentError(group, errorCode)
          maybePrepareRebalance(group)
        } else {
          setAndPropagateAssignment(group, assignment)
          group.transitionTo(Stable)
        }
      }
    }
}))

setAndPropagateAssignment主要如下:

  private def setAndPropagateAssignment(group: GroupMetadata, assignment: Map[String, Array[Byte]]) {
    assert(group.is(AwaitingSync))
    // 将分配结果更新到GroupMetadata维护的每个MemberMetadata中
    group.allMemberMetadata.foreach(member => member.assignment = assignment(member.memberId))
    propagateAssignment(group, Errors.NONE.code)
  }

  private def propagateAssignment(group: GroupMetadata, errorCode: Short) {
    for (member <- group.allMemberMetadata) {
      if (member.awaitingSyncCallback != null) {
          // 调用每个membermetadata的回调函数,具体操作时创建syncGroupResponse对象并添加到requestChannels中等待发送
        member.awaitingSyncCallback(member.assignment, errorCode)
        member.awaitingSyncCallback = null

        // reset the session timeout for members after propagating the member's assignment.
        // This is because if any member's session expired while we were still awaiting either
        // the leader sync group or the storage callback, its expiration will be ignored and no
        // future heartbeat expectations will not be scheduled.
        // 开启等待下次心跳的延迟任务。
        completeAndScheduleNextHeartbeatExpiration(group, member)
      }
    }
  }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值