kafka消费组管理模块(四)-GroupCoordinator分析

GroupCoordinator负责对接上层KafkaApis的各种handle请求,对下封装了GroupMetadataManager的各个方法

重点分析rebalance的两个阶段JoinRequest和SyncRequest

一.JoinRequest

1.最上层由KafkaApis的handleJoinGroupRequest方法发起
case ApiKeys.JOIN_GROUP => handleJoinGroupRequest(request)
def handleJoinGroupRequest(request: RequestChannel.Request): Unit = {
  val joinGroupRequest = request.body[JoinGroupRequest]

  // 封装返回结果
  def sendResponseCallback(joinResult: JoinGroupResult): Unit = {
    def createResponse(requestThrottleMs: Int): AbstractResponse = {
      val protocolName = if (request.context.apiVersion() >= 7)
        joinResult.protocolName.orNull
      else
        joinResult.protocolName.getOrElse(GroupCoordinator.NoProtocol)

      val responseBody = new JoinGroupResponse(
        new JoinGroupResponseData()
          .setThrottleTimeMs(requestThrottleMs)
          .setErrorCode(joinResult.error.code)
          .setGenerationId(joinResult.generationId)
          .setProtocolType(joinResult.protocolType.orNull)
          .setProtocolName(protocolName)
          .setLeader(joinResult.leaderId)
          .setMemberId(joinResult.memberId)
          .setMembers(joinResult.members.asJava)
      )

      trace("Sending join group response %s for correlation id %d to client %s."
        .format(responseBody, request.header.correlationId, request.header.clientId))
      responseBody
    }
    sendResponseMaybeThrottle(request, createResponse)
  }
//校验参数合法性
  if (joinGroupRequest.data.groupInstanceId != null && config.interBrokerProtocolVersion < KAFKA_2_3_IV0) {
    // Only enable static membership when IBP >= 2.3, because it is not safe for the broker to use the static member logic
    // until we are sure that all brokers support it. If static group being loaded by an older coordinator, it will discard
    // the group.instance.id field, so static members could accidentally become "dynamic", which leads to wrong states.
    sendResponseCallback(JoinGroupResult(JoinGroupRequest.UNKNOWN_MEMBER_ID, Errors.UNSUPPORTED_VERSION))
//校验acl权限
  } else if (!authorize(request.context, READ, GROUP, joinGroupRequest.data.groupId)) {
    sendResponseCallback(JoinGroupResult(JoinGroupRequest.UNKNOWN_MEMBER_ID, Errors.GROUP_AUTHORIZATION_FAILED))
  } else {
    val groupInstanceId = Option(joinGroupRequest.data.groupInstanceId)

    // Only return MEMBER_ID_REQUIRED error if joinGroupRequest version is >= 4
    // and groupInstanceId is configured to unknown.
    val requireKnownMemberId = joinGroupRequest.version >= 4 && groupInstanceId.isEmpty

    // let the coordinator handle join-group
    val protocols = joinGroupRequest.data.protocols.valuesList.asScala.map(protocol =>
      (protocol.name, protocol.metadata)).toList

    groupCoordinator.handleJoinGroup(
      joinGroupRequest.data.groupId,
      joinGroupRequest.data.memberId,
      groupInstanceId,
      requireKnownMemberId,
      request.header.clientId,
      request.context.clientAddress.toString,
      joinGroupRequest.data.rebalanceTimeoutMs,
      joinGroupRequest.data.sessionTimeoutMs,
      joinGroupRequest.data.protocolType,
      protocols,
      sendResponseCallback)
  }
}

2.groupCoordinator.handleJoinGroup

def handleJoinGroup(groupId: String,
                    memberId: String,
                    groupInstanceId: Option[String],
                    requireKnownMemberId: Boolean,
                    clientId: String,
                    clientHost: String,
                    rebalanceTimeoutMs: Int,
                    sessionTimeoutMs: Int,
                    protocolType: String,
                    protocols: List[(String, Array[Byte])],
                    responseCallback: JoinCallback): Unit = {
 //校验是否由本broker处理,组状态是否允许join
  validateGroupStatus(groupId, ApiKeys.JOIN_GROUP).foreach { error =>
    responseCallback(JoinGroupResult(memberId, error))
    return
  }
//校验sessionTimeout
  if (sessionTimeoutMs < groupConfig.groupMinSessionTimeoutMs ||
    sessionTimeoutMs > groupConfig.groupMaxSessionTimeoutMs) {
    responseCallback(JoinGroupResult(memberId, Errors.INVALID_SESSION_TIMEOUT))
  } else {
    val isUnknownMember = memberId == JoinGroupRequest.UNKNOWN_MEMBER_ID
    // group is created if it does not exist and the member id is UNKNOWN. if member
    // is specified but group does not exist, request is rejected with UNKNOWN_MEMBER_ID
    groupManager.getOrMaybeCreateGroup(groupId, isUnknownMember) match {
      case None =>
        responseCallback(JoinGroupResult(memberId, Errors.UNKNOWN_MEMBER_ID))
      case Some(group) =>
        group.inLock {
           //判断是不是达到组成员上限 broker.config的group.max.size配置,默认21亿
          if (!acceptJoiningMember(group, memberId)) {
            group.remove(memberId)
            group.removeStaticMember(groupInstanceId)
            responseCallback(JoinGroupResult(JoinGroupRequest.UNKNOWN_MEMBER_ID, Errors.GROUP_MAX_SIZE_REACHED))
          //未知成员处理方式
          } else if (isUnknownMember) {
            doUnknownJoinGroup(group, groupInstanceId, requireKnownMemberId, clientId, clientHost, rebalanceTimeoutMs, sessionTimeoutMs, protocolType, protocols, responseCallback)
          //已有成员处理方式
          } else {
            doJoinGroup(group, memberId, groupInstanceId, clientId, clientHost, rebalanceTimeoutMs, sessionTimeoutMs, protocolType, protocols, responseCallback)
          }

          // attempt to complete JoinGroup
          if (group.is(PreparingRebalance)) {
            joinPurgatory.checkAndComplete(GroupKey(group.groupId))
          }
        }
    }
  }
}

3.groupCoordinator.doUnknownJoinGroup

private def doUnknownJoinGroup(group: GroupMetadata,
                               groupInstanceId: Option[String],
                               requireKnownMemberId: Boolean,
                               clientId: String,
                               clientHost: String,
                               rebalanceTimeoutMs: Int,
                               sessionTimeoutMs: Int,
                               protocolType: String,
                               protocols: List[(String, Array[Byte])],
                               responseCallback: JoinCallback): Unit = {
  group.inLock {
    if (group.is(Dead)) {
      // if the group is marked as dead, it means some other thread has just removed the group
      // from the coordinator metadata; it is likely that the group has migrated to some other
      // coordinator OR the group is in a transient unstable phase. Let the member retry
      // finding the correct coordinator and rejoin.
      responseCallback(JoinGroupResult(JoinGroupRequest.UNKNOWN_MEMBER_ID, Errors.COORDINATOR_NOT_AVAILABLE))
    } else if (!group.supportsProtocols(protocolType, MemberMetadata.plainProtocolSet(protocols))) {
      responseCallback(JoinGroupResult(JoinGroupRequest.UNKNOWN_MEMBER_ID, Errors.INCONSISTENT_GROUP_PROTOCOL))
    } else {
      //生成memberId
      val newMemberId = group.generateMemberId(clientId, groupInstanceId)
      ...static member的高级用法略去...
      addMemberAndRebalance(rebalanceTimeoutMs, sessionTimeoutMs, newMemberId, groupInstanceId,
          clientId, clientHost, protocolType, protocols, group, responseCallback)
      }
    }
  }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值