SparkCore — BlockManagerMaster信息注册

BlockManagerMaster

  上一篇博客简单讲解了BlockManager的运行机制,BlockManager在创建的时候首先会向BlockManagerMaster进行注册,下面我们来看源码中,在BlockManagerMaster上是如何注册的:

register注册函数
/**
    *    注册BlockManager
    */
  private def register(id: BlockManagerId, maxMemSize: Long, slaveEndpoint: RpcEndpointRef) {
    val time = System.currentTimeMillis()
    // 首先判断,如果本地HashMap中没有指定的BlockManagerId,说明还没有注册过
    // 先去注册当前这个BlockManager
    if (!blockManagerInfo.contains(id)) {
      // 根据BlockManager对应的executorID找到对应的BlockManagerInfo
      // 这里做了一个安全判断,如果BlockManagerInfo map里。没有BlockManagerId
      // 那么BlockManagerIdByExecutor map里也应该没有。如果有的话,那么需要做一下清理
      blockManagerIdByExecutor.get(id.executorId) match {
        case Some(oldId) =>
          // A block manager of the same executor already exists, so remove it (assumed dead)
          logError("Got two different block manager registrations on same executor - "
              + s" will replace old one $oldId with new one $id")
          // 从内存中,移除executorId相关的BlockManagerInfo
          removeExecutor(id.executorId)
        case None =>
      }
      logInfo("Registering block manager %s with %s RAM, %s".format(
        id.hostPort, Utils.bytesToString(maxMemSize), id))

      // 往blockManagerIdByExecutor map中保持一份executorId到blockManagerId的映射
      blockManagerIdByExecutor(id.executorId) = id

      // 为当前BlockManagerId创建一份BlockManagerInfo,并往blockManagerInfo map中保存一份
      // BlockManagerId到BlockManagerInfo的映射
      blockManagerInfo(id) = new BlockManagerInfo(
        id, System.currentTimeMillis(), maxMemSize, slaveEndpoint)
    }
    listenerBus.post(SparkListenerBlockManagerAdded(time, id, maxMemSize))
  }

  这个函数是在BlockManagerMasterEndpoint组件中,这个组件维护BlockManagerMaster与BlockManager的通信。
  首先判断当前BlockManager是否注册过,如果还没有注册,那么再做一个安全判断,根据BlockManager对应的executorID找到对应的BlockManagerInfo,看能否找到,假如有的话,就移除executor相关的BlockManagerInfo(这里就是看之前注册的executorId中是否有相同的BlockMangerId);接着就开始注册信息,往blockManagerIdByExecutor map中保持一份executorId到blockManagerId的映射,并为当前BlockManagerId创建一份BlockManagerInfo,并往BlockManagerInfo map中保存一份BlockManagerId到BlockManagerInfo的映射,到这里注册就结束。

UpdateBlockInfo更新Block信息

  接着我们看一下更新BlockInfo,也即如果每个BlockManager上Block发生了变换,那么都要发送UpdateBlockInfo请求到BlockManagerMaster,进行BlockInfo的更新。我们看BlockManagerMaster接收到更新消息如何处理,代码如下:

private def updateBlockInfo(
      blockManagerId: BlockManagerId,
      blockId: BlockId,
      storageLevel: StorageLevel,
      memSize: Long,
      diskSize: Long,
      externalBlockStoreSize: Long): Boolean = {

    // 如果不包含这个BlockManagerId,并且是在Driver端,则啥也不做返回
    if (!blockManagerInfo.contains(blockManagerId)) {
      if (blockManagerId.isDriver && !isLocal) {
        // We intentionally do not register the master (except in local mode),
        // so we should not indicate failure.
        return true
      } else {
        return false
      }
    }

    // 如果是空,更新一下时间
    if (blockId == null) {
      blockManagerInfo(blockManagerId).updateLastSeenMs()
      return true
    }
    // 调用updateBlockInfo对block信息进行更新
    blockManagerInfo(blockManagerId).updateBlockInfo(
      blockId, storageLevel, memSize, diskSize, externalBlockStoreSize)

    // 这里每一个Block可能会在多个BlockManager上
    // 如果将StorageLevel设置为 _2 这种格式,就需要将Block replicate一份到其他BlockManager上
    // blockLocations map保存了每个BlockId对应的BlockManagerId的set集合
    // 这里会更新blockLocations中的信息,使用set集合自动去重
    var locations: mutable.HashSet[BlockManagerId] = null
    if (blockLocations.containsKey(blockId)) {
      locations = blockLocations.get(blockId)
    } else {
      locations = new mutable.HashSet[BlockManagerId]
      blockLocations.put(blockId, locations)
    }

    // 只对持久化级别是 Disk、Memory和OffHeap三种情况,进行添加
    if (storageLevel.isValid) {
      locations.add(blockManagerId)
    } else {
      locations.remove(blockManagerId)
    }

    // Remove the block from master tracking if it has been removed on all slaves.
    // 如果各个节点上的block都被删除了,那么也清楚Master上相应的Block的信息
    if (locations.size == 0) {
      blockLocations.remove(blockId)
    }
    true
  }

  简单分析一下,就是对BlockManager的信息进行更新,调用BlockManagerInfo的updateBlockInfo对Block信息进行更新,这里更新主要是给每个BlockId创建一份BlockStatus,根据持久化级别(Disk、Memory或OffHeap),进行计算,更新到BlockManagerInfo map中;然后就是假设Block持久化级别是 _2 级别的(比如MEMORY_AND_DISK_2),就需要将Block replicate一份到其他Block上去,blockLocations map保存了每个BlockId对应的BlockManagerId的集合(可能不在一个节点上),这里就是更新blockLocations的信息,使用set集合去重BlockManagerId。最后就是进行一些删除操作。
  简单总结一下,BlockManager信息注册比较重要的两个一个数注册register,一个是updateBlockInfo;其中第一个就是依据BlockManagerId生成一个BlockManagerInfo并进行保存;第二个就是更新BlockManagerInfo中的BlockStatus。(附上比较重要的组件的定义)

  // 这个Map、映射了block manager id到block manager的info
  // BlockManagerId - BlockManagerInfo的映射
  // BlockManagerMaster要负责维护每个BlockManager的BlockManagerInfo
  private val blockManagerInfo = new mutable.HashMap[BlockManagerId, BlockManagerInfo]

  // 映射每个executor ID - BlockManagerId
  private val blockManagerIdByExecutor = new mutable.HashMap[String, BlockManagerId]
  
  // BlockManagerInfo管理了每个BlockManager内部的BlockId - BlockStatus
  private val _blocks = new JHashMap[BlockId, BlockStatus]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值