Kafka 副本管理模块(七):ReplicaManager 副本管理之ISR变更处理

        除了读写副本、管理分区和副本的功能之外,副本管理器还有一个重要的功能,那就是管理 ISR。这里的管理主要体现在两个方法:

  • maybeShrinkIsr 方法:作用是阶段性地查看 ISR 中的副本集合是否需要收缩;收缩是指,把 ISR 副本集合中那些与 Leader 差距过大的副本移除的过程。所谓的差距过大,就是 ISR 中 Follower 副本滞后 Leader 副本的时间,超过了 Broker 端参数 replica.lag.time.max.ms 值的 1.5 倍。
  • maybePropagateIsrChanges 方法:作用是定期向集群 Broker 传播 ISR 的变更。

maybeShrinkIsr 方法

        maybeShrinkIsr的逻辑就是遍历该副本管理器上所有分区对象,依次为这些分区中状态为 Online 的分区,执行 Partition 类的 maybeShrinkIsr 方法:

  private def maybeShrinkIsr(): Unit = {
    trace("Evaluating ISR list of partitions to see which replicas can be removed from the ISR")

    // Shrink ISRs for non offline partitions
    allPartitions.keys.foreach { topicPartition =>
      nonOfflinePartition(topicPartition).foreach(_.maybeShrinkIsr(config.replicaLagTimeMaxMs))
    }
  }

它实际上执行了partition的maybeShrinkIsr方法

  def maybeShrinkIsr(replicaMaxLagTimeMs: Long): Unit = {
    val leaderHWIncremented = inWriteLock(leaderIsrUpdateLock) {
      leaderLogIfLocal match {
        // 如果是Leader副本
        case Some(leaderLog) =>
          // 获取不同步的副本Id列表
          val outOfSyncReplicaIds = getOutOfSyncReplicas(replicaMaxLagTimeMs)
          // 如果存在不同步的副本Id列表
          if (outOfSyncReplicaIds.nonEmpty) {
            // 计算收缩之后的ISR列表
            val newInSyncReplicaIds = inSyncReplicaIds -- outOfSyncReplicaIds
            assert(newInSyncReplicaIds.nonEmpty)
            info("Shrinking ISR from %s to %s. Leader: (highWatermark: %d, endOffset: %d). Out of sync replicas: %s."
              .format(inSyncReplicaIds.mkString(","),
                newInSyncReplicaIds.mkString(","),
                leaderLog.highWatermark,
                leaderLog.logEndOffset,
                outOfSyncReplicaIds.map { replicaId =>
                  s"(brokerId: $replicaId, endOffset: ${getReplicaOrException(replicaId).logEndOffset})"
                }.mkString(" ")
              )
            )

            // update ISR in zk and in cache
            // 更新ZooKeeper中分区的ISR数据以及Broker的元数据缓存中的数据
            shrinkIsr(newInSyncReplicaIds)

            // we may need to increment high watermark since ISR could be down to 1
            // 尝试更新Leader副本的高水位值
            maybeIncrementLeaderHW(leaderLog)
          } else {
            false
          }
        // 如果不是Leader副本,什么都不做
        case None => false // do nothing if no longer leader
      }
    }

    // some delayed operations may be unblocked after HW changed
    // 如果Leader副本的高水位值抬升了
    if (leaderHWIncremented)
      // 尝试解锁一下延迟请求
      tryCompleteDelayedRequests()
  }

        另外下面再介绍一下partition的maybeExpandIsr方法。

        maybeExpandIsr方法用于将指定的副本在满足条件下加入到 ISR 集合中

  private def maybeExpandIsr(followerReplica: Replica, followerFetchTimeMs: Long): Unit = {
    inWriteLock(leaderIsrUpdateLock) {
      // check if this replica needs to be added to the ISR
      leaderLogIfLocal.foreach { leaderLog => // 只有当本地副本是 leader 副本时,才执行扩张操作,因为 ISR 集合由 leader 副本维护
        // 获取 leader 副本对应的 HW 值
        val leaderHighwatermark = leaderLog.highWatermark
        // 判断当前 follower 是否应该被加入到 ISR 集合,并在成功加入后更新相关信息
        if (!inSyncReplicaIds.contains(followerReplica.brokerId)  // follower 副本不在 ISR 集合中
          && isFollowerInSync(followerReplica, leaderHighwatermark) // follower 副本的 LEO 已经追赶上 leader 副本的 HW 值
        ) {
          val newInSyncReplicaIds = inSyncReplicaIds + followerReplica.brokerId
          info(s"Expanding ISR from ${inSyncReplicaIds.mkString(",")} " +
            s"to ${newInSyncReplicaIds.mkString(",")}")

          // update ISR in ZK and cache
          expandIsr(newInSyncReplicaIds)
        }
      }
    }
  }

maybePropagateIsrChanges 方法

        ISR 收缩之后,ReplicaManager 还需要将这个操作的结果传递给集群的其他 Broker,以同步这个操作的结果。这是由 ISR 通知事件来完成的。

  //  周期性将 ISR 集合发生变化的 topic 副本信息更新到 ZK 相应节点下,
  //  Kafka 集群控制器基于 ZK 的 Watcher 机制监听相应节点,并在节点内容发生变化时向所有可用的 broker 节点发送 UpdateMetadataRequest 请求,
  //  以更新相应 broker 节点本地管理的整个集群中所有分区的状态信息。
  def maybePropagateIsrChanges(): Unit = {
    val now = System.currentTimeMillis()
    isrChangeSet synchronized {
      // ISR变更传播的条件,需要同时满足:
      // 1. 存在尚未被传播的ISR变更
      // 2. 最近5秒没有任何ISR变更,或者自上次ISR变更已经有超过1分钟的时间
      if (isrChangeSet.nonEmpty &&
        (lastIsrChangeMs.get() + ReplicaManager.IsrChangePropagationBlackOut < now ||
          lastIsrPropagationMs.get() + ReplicaManager.IsrChangePropagationInterval < now)) {
        // 创建ZooKeeper相应的Znode节点
        zkClient.propagateIsrChanges(isrChangeSet)
        // 清空isrChangeSet集合
        isrChangeSet.clear()
        // 更新最近ISR变更时间戳
        lastIsrPropagationMs.set(now)
      }
    }
  }

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值