BlockManager解密进阶

内容:

1、BlockManager源码详解;

2、BlockManagerMaster源码详解;

3、BlockManager具体数据读写源码解析;;

如果想写高效的程序,性能调优方面的内容,39、BlockManager,40、CacheManager,41、CheckPoint课里面关于数据存储方面的内容,在实际开发中是绝对重要的内容,一定要搞懂!!!

==========BlockManager源码详解 ============

1、BlockManager既会运行在Executor上面也会运行在Driver上面,Driver上的是管理整个集群所有的BlockManager的,Executor在实例化的时候一定会进行Executor上的BlockManager的实例化

if (!isLocal) {
  env.metricsSystem.registerSource(executorSource)
  env.blockManager.initialize(conf.getAppId)
}

同时在Executor实例化 的时候,会创建BlockManagerSlaveEndpoint这个消息循环体,它会接收Driver中的BlockManangerMaster发送过来的指令,例如删除Block等;

2、BlockManager也是Master/Slave结构的(Master/Slave结构 一切都是Master触发,Slave只有傻傻干活的份―);

3、BlockManager主要提供本地或者远程的数据的读取和写入,可以基于内存、磁盘、对外(比如Tackyon等),SPark+Tackyon是超级好的组合;

4、BlockManagerMaster、MemoryManager、MapOutputTracker、BlockTransferService是BlockManager的一个元,

MapOutputTracker是shuffleMapTask输出的位置记录的对象 ,记录好了可以供下一个Stage去使用,

BlockTransferService用于不同BlockManager之间的网络通信实现数据操作,

Block是Spark运行过程中最小的数据抽象单位,可以放在内存、磁盘、Tackyon等;

/**
 * Manager running on every node (driver and executors) which provides interfaces for putting and
 * retrieving blocks both locally and remotely into various stores (memory, disk, and off-heap).
 *
 * Note that #initialize() must be called before the BlockManager is usable.
 */
private[spark] class BlockManager(
    executorId: String,
    rpcEnv: RpcEnv,
    val master: BlockManagerMaster,
    defaultSerializer: Serializer,
    val conf: SparkConf,
    memoryManager: MemoryManager,
    mapOutputTracker: MapOutputTracker,
    shuffleManager: ShuffleManager,
    blockTransferService: BlockTransferService,
    securityManager: SecurityManager,
    numUsableCores: Int)
  extends BlockDataManager with Logging {

5、用来管理磁盘的读写的diskBlockManager;

val diskBlockManager new DiskBlockManager(thisconf)

6、缓存池

private val futureExecutionContext = ExecutionContext.fromExecutorService(
  ThreadUtils.newDaemonCachedThreadPool("block-manager-future"128))

7、memoryStore、diskStore、externalBlockStore(一般实际角度就是Tackyon)

private[spark] val memoryStore new MemoryStore(thismemoryManager)
private[spark] val diskStore new DiskStore(thisdiskBlockManager)

private[spark] lazy val externalBlockStore: ExternalBlockStore = {
  externalBlockStoreInitialized true
  new ExternalBlockStore(thisexecutorId)
}
memoryManager.setMemoryStore(memoryStore)

8、来看基于应用程序的ID初始化BlockManager,它不是在构造器中使用,因为在BlockManager在实例化的时候,可能还不知道appId,应用程序启动之后appID是SchedulerBackend向Master注册时获得的,

初始化的时候初始化了BlockTransferService(进行网络通信的)、ShuffleClient、给BlockManangerMaster注册、启动BlockManagerWorkerEndpoint、注册本地shuffle

/**
 * Initializes the BlockManager with the given appId. This is not performed in the constructor as
 * the appId may not be known at BlockManager instantiation time (in particular for the driver,
 * where it is only learned after registration with the TaskScheduler).
 *
 * This method initializes the BlockTransferService and ShuffleClient, registers with the
 * BlockManagerMaster, starts the BlockManagerWorker endpoint, and registers with a local shuffle
 * service if configured.
 */
def initialize(appId: String): Unit = {
  blockTransferService.init(this)
  shuffleClient.init(appId)

  blockManagerId BlockManagerId(
    executorIdblockTransferService.hostNameblockTransferService.port)

  shuffleServerId if (externalShuffleServiceEnabled) {
    logInfo(s"external shuffle service port = $externalShuffleServicePort")
    BlockManagerId(executorIdblockTransferService.hostNameexternalShuffleServicePort)
  } else {
    blockManagerId
  }

  master.registerBlockManager(blockManagerIdmaxMemoryslaveEndpoint)

  // Register Executors' configuration with the local shuffle service, if one should exist.
  if (externalShuffleServiceEnabled && !blockManagerId.isDriver) {
    registerWithExternalShuffleServer()
  }
}

/** Register the BlockManager's id with the driver. */
def registerBlockManager(
    blockManagerId: BlockManagerIdmaxMemSize: Long, slaveEndpoint: RpcEndpointRef): Unit = {
  logInfo("Trying to register BlockManager")
  tell(RegisterBlockManager(blockManagerIdmaxMemSizeslaveEndpoint))
  logInfo("Registered BlockManager")
}

/** Send a one-way message to the master endpoint, to which we expect it to reply with true. */
private def tell(message: Any) {
  if (!driverEndpoint.askWithRetry[Boolean](message)) {
    throw new SparkException("BlockManagerMasterEndpoint returned false, expected true.")
  }
}

其实上面的drvierEndpoint真正是BlockManagerMasterEndpoint的对象实例

9、就是说从上面一些代码和理论中得出:当BlockManagerSlaveEndpoint实例化后,Executor上的BlockManager需要向Driver上的BlockManagerMasterEndpoint注册,BlockManagerMasterEndpoint接收到注册BlockManager的信息

case RegisterBlockManager(blockManagerIdmaxMemSizeslaveEndpoint) =>
  register(blockManagerIdmaxMemSizeslaveEndpoint)
  context.reply(true)

private def register(id: BlockManagerIdmaxMemSize: Long, slaveEndpoint: RpcEndpointRef) {
  val time = System.currentTimeMillis()
  if (!blockManagerInfo.contains(id)) {
    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")
        removeExecutor(id.executorId)
      case None =>
    }
    logInfo("Registering block manager %s with %s RAM, %s".format(
      id.hostPortUtils.bytesToString(maxMemSize)id))

    blockManagerIdByExecutor(id.executorId) = id

    blockManagerInfo(id) = new BlockManagerInfo(
      idSystem.currentTimeMillis()maxMemSizeslaveEndpoint)
  }
  listenerBus.post(SparkListenerBlockManagerAdded(timeidmaxMemSize))
}

10、当前BlockStatus的获取

/**
 * Return the updated storage status of the block with the given ID. More specifically, if
 * the block is dropped from memory and possibly added to disk, return the new storage level
 * and the updated in-memory and on-disk sizes.
 */
private def getCurrentBlockStatus(blockId: BlockIdinfo: BlockInfo): BlockStatus = {
  info.synchronized {
    info.level match {
      case null =>
        BlockStatus(StorageLevel.NONE0L0L0L)
      case level =>
        val inMem = level.useMemory && memoryStore.contains(blockId)
        val inExternalBlockStore = level.useOffHeap && externalBlockStore.contains(blockId)
        val onDisk = level.useDisk && diskStore.contains(blockId)
        val deserialized = if (inMem) level.deserialized else false
        val replication = if (inMem || inExternalBlockStore || onDisk) level.replication else 1
        val storageLevel =
          StorageLevel(onDiskinMeminExternalBlockStoredeserializedreplication)
        val memSize = if (inMem) memoryStore.getSize(blockId) else 0L
        val externalBlockStoreSize =
          if (inExternalBlockStore) externalBlockStore.getSize(blockId) else 0L
        val diskSize = if (onDisk) diskStore.getSize(blockId) else 0L
        BlockStatus(storageLevelmemSizediskSizeexternalBlockStoreSize)
    }
  }
}

11、根据BlockId获得这个BlockId所在的BlockMananger

/**
 * Get locations of an array of blocks.
 */
private def getLocationBlockIds(blockIds: Array[BlockId]): Array[Seq[BlockManagerId]] = {
  val startTimeMs = System.currentTimeMillis
  val locations = master.getLocations(blockIds).toArray
  logDebug("Got multiple block location in %s".format(Utils.getUsedTimeMs(startTimeMs)))
  locations
}

/** Get locations of multiple blockIds from the driver */
def getLocations(blockIds: Array[BlockId]): IndexedSeq[Seq[BlockManagerId]] = {
  driverEndpoint.askWithRetry[IndexedSeq[Seq[BlockManagerId]]](
    GetLocationsMultipleBlockIds(blockIds))
}

private def getLocationsMultipleBlockIds(
    blockIds: Array[BlockId]): IndexedSeq[Seq[BlockManagerId]] = {
  blockIds.map(blockId => getLocations(blockId))
}

private def getLocations(blockId: BlockId): Seq[BlockManagerId] = {
  if (blockLocations.containsKey(blockId)) blockLocations.get(blockId).toSeq else Seq.empty
}

// Mapping from block id to the set of block managers that have the block.
private val blockLocations new JHashMap[BlockIdmutable.HashSet[BlockManagerId]]

为什么这个value是HashSet?因为每个Block一般情况下有副本!!!不同副本对应的BlockId不一样。

12、从local block manager上获取数据的getLocal,读取的时候会用同步代码块,如果是useDisk,注意代码的牛叉的地方,会部分存内存

/**
 * Get block from local block manager.
 */
def getLocal(blockId: BlockId): Option[BlockResult] = {
  logDebug(s"Getting local block $blockId")
  doGetLocal(blockIdasBlockResult = true).asInstanceOf[Option[BlockResult]]
}

private def doGetLocal(blockId: BlockIdasBlockResult: Boolean): Option[Any] = {
  val info = blockInfo.get(blockId).orNull
  if (info != null) {
    info.synchronized {
      // Double check to make sure the block is still there. There is a small chance that the
      // block has been removed by removeBlock (which also synchronizes on the blockInfo object).
      // Note that this only checks metadata tracking. If user intentionally deleted the block
      // on disk or from off heap storage without using removeBlock, this conditional check will
      // still pass but eventually we will get an exception because we can't find the block.
      if (blockInfo.get(blockId).isEmpty) {
        logWarning(s"Block $blockId had been removed")
        return None
      }

      // If another thread is writing the block, wait for it to become ready.
      if (!info.waitForReady()) {
        // If we get here, the block write failed.
        logWarning(s"Block $blockId was marked as failure.")
        return None
      }

      val level = info.level
      logDebug(s"Level for block $blockId is $level")

      // Look for the block in memory
      if (level.useMemory) {
        logDebug(s"Getting block $blockId from memory")
        val result = if (asBlockResult) {
          memoryStore.getValues(blockId).map(new BlockResult(_DataReadMethod.Memoryinfo.size))
        } else {
          memoryStore.getBytes(blockId)
        }
        result match {
          case Some(values) =>
            return result
          case None =>
            logDebug(s"Block $blockId not found in memory")
        }
      }

      // Look for the block in external block store
      if (level.useOffHeap) {
        logDebug(s"Getting block $blockId from ExternalBlockStore")
        if (externalBlockStore.contains(blockId)) {
          val result = if (asBlockResult) {
            externalBlockStore.getValues(blockId)
              .map(new BlockResult(_DataReadMethod.Memoryinfo.size))
          } else {
            externalBlockStore.getBytes(blockId)
          }
          result match {
            case Some(values) =>
              return result
            case None =>
              logDebug(s"Block $blockId not found in ExternalBlockStore")
          }
        }
      }

      // Look for block on disk, potentially storing it back in memory if required
      if (level.useDisk) {
        logDebug(s"Getting block $blockId from disk")
        val bytes: ByteBuffer = diskStore.getBytes(blockId) match {
          case Some(b) => b
          case None =>
            throw new BlockException(
              blockIds"Block $blockId not found on disk, though it should be")
        }
        assert(== bytes.position())

        if (!level.useMemory) {
          // If the block shouldn't be stored in memory, we can just return it
          if (asBlockResult) {
            return Some(new BlockResult(dataDeserialize(blockIdbytes)DataReadMethod.Disk,
              info.size))
          } else {
            return Some(bytes)
          }
        } else {
          // Otherwise, we also have to store something in the memory store
          if (!level.deserialized || !asBlockResult) {
            /* We'll store the bytes in memory if the block's storage level includes
             * "memory serialized", or if it should be cached as objects in memory
             * but we only requested its serialized bytes. */
            memoryStore.putBytes(blockIdbytes.limit() => {
              // https://issues.apache.org/jira/browse/SPARK-6076
              // If the file size is bigger than the free memory, OOM will happen. So if we cannot
              // put it into MemoryStore, copyForMemory should not be created. That's why this
              // action is put into a `() => ByteBuffer` and created lazily.
              val copyForMemory = ByteBuffer.allocate(bytes.limit)
              copyForMemory.put(bytes)
            })
            bytes.rewind()
          }
          if (!asBlockResult) {
            return Some(bytes)
          } else {
            val values = dataDeserialize(blockIdbytes)
            if (level.deserialized) {
              // Cache the values before returning them
              val putResult = memoryStore.putIterator(
                blockIdvalueslevelreturnValues = trueallowPersistToDisk = false)
              // The put may or may not have succeeded, depending on whether there was enough
              // space to unroll the block. Either way, the put here should return an iterator.
              putResult.data match {
                case Left(it) =>
                  return Some(new BlockResult(itDataReadMethod.Diskinfo.size))
                case _ =>
                  // This only happens if we dropped the values back to disk (which is never)
                  throw new SparkException("Memory store did not return an iterator!")
              }
            } else {
              return Some(new BlockResult(valuesDataReadMethod.Diskinfo.size))
            }
          }
        }
      }
    }
  } else {
    logDebug(s"Block $blockId not registered locally")
  }
  None
}

13、从远程节点获得数据,一般blockId对应的数据有若干个副本,那只需要读取一个副本上的数据,先从master上获得blockId所在的位置,然后Random.shuffle(是为了负载均衡),然后通过blockTransferService获取数据

/**
 * Get block from remote block managers.
 */
def getRemote(blockId: BlockId): Option[BlockResult] = {
  logDebug(s"Getting remote block $blockId")
  doGetRemote(blockIdasBlockResult = true).asInstanceOf[Option[BlockResult]]
}

private def doGetRemote(blockId: BlockIdasBlockResult: Boolean): Option[Any] = {
  require(blockId != null"BlockId is null")
  val locations = Random.shuffle(master.getLocations(blockId))
  var numFetchFailures = 0
  for (loc <- locations) {
    logDebug(s"Getting remote block $blockId from $loc")
    val data = try {
      blockTransferService.fetchBlockSync(
        loc.hostloc.portloc.executorIdblockId.toString).nioByteBuffer()
    } catch {
      case NonFatal(e) =>
        numFetchFailures += 1
        if (numFetchFailures == locations.size) {
          // An exception is thrown while fetching this block from all locations
          throw new BlockFetchException(s"Failed to fetch block from" +
            s" ${locations.size} locations. Most recent failure cause:"e)
        } else {
          // This location failed, so we retry fetch from a different one by returning null here
          logWarning(s"Failed to fetch remote block $blockId +
            s"from $loc (failed attempt $numFetchFailures)"e)
          null
        }
    }

    if (data != null) {
      if (asBlockResult) {
        return Some(new BlockResult(
          dataDeserialize(blockIddata),
          DataReadMethod.Network,
          data.limit()))
      } else {
        return Some(data)
      }
    }
    logDebug(s"The value of block $blockId is null")
  }
  logDebug(s"Block $blockId not found")
  None
}

这个返回ManagedBuffer

/**
 * A special case of [[fetchBlocks]], as it fetches only one block and is blocking.
 *
 * It is also only available after [[init]] is invoked.
 */
def fetchBlockSync(host: Stringport: Int, execId: StringblockId: String): ManagedBuffer = {
  // A monitor for the thread to wait on.
  val result = Promise[ManagedBuffer]()
  fetchBlocks(hostportexecIdArray(blockId),
    new BlockFetchingListener {
      override def onBlockFetchFailure(blockId: Stringexception: Throwable): Unit = {
        result.failure(exception)
      }
      override def onBlockFetchSuccess(blockId: Stringdata: ManagedBuffer): Unit = {
        val ret = ByteBuffer.allocate(data.size.toInt)
        ret.put(data.nioByteBuffer())
        ret.flip()
        result.success(new NioManagedBuffer(ret))
      }
    })

  Await.result(result.futureDuration.Inf)
}

/**
 * Fetch a sequence of blocks from a remote node asynchronously,
 * available only after [[init]] is invoked.
 *
 * Note that this API takes a sequence so the implementation can batch requests, and does not
 * return a future so the underlying implementation can invoke onBlockFetchSuccess as soon as
 * the data of a block is fetched, rather than waiting for all blocks to be fetched.
 */
override def fetchBlocks(
    host: String,
    port: Int,
    execId: String,
    blockIds: Array[String],
    listener: BlockFetchingListener): Unit

在NettyBlockTransferService中实现fetch:

override def fetchBlocks(
    host: String,
    port: Int,
    execId: String,
    blockIds: Array[String],
    listener: BlockFetchingListener): Unit = {
  logTrace(s"Fetch blocks from $host:$port (executor id $execId)")
  try {
    val blockFetchStarter = new RetryingBlockFetcher.BlockFetchStarter {
      override def createAndStart(blockIds: Array[String]listener: BlockFetchingListener) {
        val client = clientFactory.createClient(hostport)
        new OneForOneBlockFetcher(clientappIdexecIdblockIds.toArraylistener).start()
      }
    }

    val maxRetries = transportConf.maxIORetries()
    if (maxRetries > 0) {
      // Note this Fetcher will correctly handle maxRetries == 0; we avoid it just in case there's
      // a bug in this code. We should remove the if statement once we're sure of the stability.
      new RetryingBlockFetcher(transportConfblockFetchStarterblockIdslistener).start()
    } else {
      blockFetchStarter.createAndStart(blockIdslistener)
    }
  } catch {
    case e: Exception =>
      logError("Exception while beginning fetchBlocks"e)
      blockIds.foreach(listener.onBlockFetchFailure(_e))
  }
}

14、写数据

def putIterator(
    blockId: BlockId,
    values: Iterator[Any],
    level: StorageLevel,
    tellMaster: Boolean true,
    effectiveStorageLevel: Option[StorageLevel] = None): Seq[(BlockIdBlockStatus)] = {
  require(values != null"Values is null")
  doPut(blockIdIteratorValues(values)leveltellMastereffectiveStorageLevel)
}

def putArray(
    blockId: BlockId,
    values: Array[Any],
    level: StorageLevel,
    tellMaster: Boolean = true,
    effectiveStorageLevel: Option[StorageLevel] = None): Seq[(BlockIdBlockStatus)] = {
  require(values != null"Values is null")
  doPut(blockIdArrayValues(values)leveltellMastereffectiveStorageLevel)
}

def putBytes(
    blockId: BlockId,
    bytes: ByteBuffer,
    level: StorageLevel,
    tellMaster: Boolean true,
    effectiveStorageLevel: Option[StorageLevel] = None): Seq[(BlockIdBlockStatus)] = {
  require(bytes != null"Bytes is null")
  doPut(blockIdByteBufferValues(bytes)leveltellMastereffectiveStorageLevel)
}

他们都是调用的doPut,如果replication大于1,则要进行replicate操作:

private def doPut(
    blockId: BlockId,
    data: BlockValues,
    level: StorageLevel,
    tellMaster: Boolean true,
    effectiveStorageLevel: Option[StorageLevel] = None)
  : Seq[(BlockIdBlockStatus)] = {

  require(blockId != null"BlockId is null")
  require(level != null && level.isValid"StorageLevel is null or invalid")
  effectiveStorageLevel.foreach { level =>
    require(level != null && level.isValid"Effective StorageLevel is null or invalid")
  }

  // Return value
  val updatedBlocks = new ArrayBuffer[(BlockIdBlockStatus)]

  /* Remember the block's storage level so that we can correctly drop it to disk if it needs
   * to be dropped right after it got put into memory. Note, however, that other threads will
   * not be able to get() this block until we call markReady on its BlockInfo. */
  val putBlockInfo = {
    val tinfo = new BlockInfo(leveltellMaster)
    // Do atomically !
    val oldBlockOpt = blockInfo.putIfAbsent(blockIdtinfo)
    if (oldBlockOpt.isDefined) {
      if (oldBlockOpt.get.waitForReady()) {
        logWarning(s"Block $blockId already exists on this machine; not re-adding it")
        return updatedBlocks
      }
      // TODO: So the block info exists - but previous attempt to load it (?) failed.
      // What do we do now ? Retry on it ?
      oldBlockOpt.get
    } else {
      tinfo
    }
  }

  val startTimeMs = System.currentTimeMillis

  /* If we're storing values and we need to replicate the data, we'll want access to the values,
   * but because our put will read the whole iterator, there will be no values left. For the
   * case where the put serializes data, we'll remember the bytes, above; but for the case where
   * it doesn't, such as deserialized storage, let's rely on the put returning an Iterator. */
  var valuesAfterPut: Iterator[Any] = null

  // Ditto for the bytes after the put
  var bytesAfterPut: ByteBuffer = null

  // Size of the block in bytes
  var size = 0L

  // The level we actually use to put the block
  val putLevel = effectiveStorageLevel.getOrElse(level)

  // If we're storing bytes, then initiate the replication before storing them locally.
  // This is faster as data is already serialized and ready to send.
  val replicationFuture = data match {
    case b: ByteBufferValues if putLevel.replication > =>
      // Duplicate doesn't copy the bytes, but just creates a wrapper
      val bufferView = b.buffer.duplicate()
      Future {
        // This is a blocking action and should run in futureExecutionContext which is a cached
        // thread pool
        replicate(blockIdbufferViewputLevel)
      }(futureExecutionContext)
    case _ => null
  }

  putBlockInfo.synchronized {
    logTrace("Put for block %s took %s to get into synchronized block"
      .format(blockIdUtils.getUsedTimeMs(startTimeMs)))

    var marked = false
    try {
      // returnValues - Whether to return the values put
      // blockStore - The type of storage to put these values into
      val (returnValuesblockStore: BlockStore) = {
        if (putLevel.useMemory) {
          // Put it in memory first, even if it also has useDisk set to true;
          // We will drop it to disk later if the memory store can't hold it.
          (truememoryStore)
        } else if (putLevel.useOffHeap) {
          // Use external block store
          (falseexternalBlockStore)
        } else if (putLevel.useDisk) {
          // Don't get back the bytes from put unless we replicate them
          (putLevel.replication > 1diskStore)
        } else {
          assert(putLevel == StorageLevel.NONE)
          throw new BlockException(
            blockIds"Attempted to put block $blockId without specifying storage level!")
        }
      }

      // Actually put the values
      val result = data match {
        case IteratorValues(iterator) =>
          blockStore.putIterator(blockIditeratorputLevelreturnValues)
        case ArrayValues(array) =>
          blockStore.putArray(blockIdarrayputLevelreturnValues)
        case ByteBufferValues(bytes) =>
          bytes.rewind()
          blockStore.putBytes(blockIdbytesputLevel)
      }
      size = result.size
      result.data match {
        case Left (newIterator) if putLevel.useMemory => valuesAfterPut = newIterator
        case Right (newBytes) => bytesAfterPut = newBytes
        case _ =>
      }

      // Keep track of which blocks are dropped from memory
      if (putLevel.useMemory) {
        result.droppedBlocks.foreach { updatedBlocks += _ }
      }

      val putBlockStatus = getCurrentBlockStatus(blockIdputBlockInfo)
      if (putBlockStatus.storageLevel != StorageLevel.NONE) {
        // Now that the block is in either the memory, externalBlockStore, or disk store,
        // let other threads read it, and tell the master about it.
        marked = true
        putBlockInfo.markReady(size)
        if (tellMaster) {
          reportBlockStatus(blockIdputBlockInfoputBlockStatus)
        }
        updatedBlocks += ((blockIdputBlockStatus))
      }
    } finally {
      // If we failed in putting the block to memory/disk, notify other possible readers
      // that it has failed, and then remove it from the block info map.
      if (!marked) {
        // Note that the remove must happen before markFailure otherwise another thread
        // could've inserted a new BlockInfo before we remove it.
        blockInfo.remove(blockId)
        putBlockInfo.markFailure()
        logWarning(s"Putting block $blockId failed")
      }
    }
  }
  logDebug("Put block %s locally took %s".format(blockIdUtils.getUsedTimeMs(startTimeMs)))

  // Either we're storing bytes and we asynchronously started replication, or we're storing
  // values and need to serialize and replicate them now:
  if (putLevel.replication > 1) {
    data match {
      case ByteBufferValues(bytes) =>
        if (replicationFuture != null) {
          Await.ready(replicationFutureDuration.Inf)
        }
      case _ =>
        val remoteStartTime = System.currentTimeMillis
        // Serialize the block if not already done
        if (bytesAfterPut == null) {
          if (valuesAfterPut == null) {
            throw new SparkException(
              "Underlying put returned neither an Iterator nor bytes! This shouldn't happen.")
          }
          bytesAfterPut = dataSerialize(blockIdvaluesAfterPut)
        }
        replicate(blockIdbytesAfterPutputLevel)
        logDebug("Put block %s remotely took %s"
          .format(blockIdUtils.getUsedTimeMs(remoteStartTime)))
    }
  }

  BlockManager.dispose(bytesAfterPut)

  if (putLevel.replication > 1) {
    logDebug("Putting block %s with replication took %s"
      .format(blockIdUtils.getUsedTimeMs(startTimeMs)))
  } else {
    logDebug("Putting block %s without replication took %s"
      .format(blockIdUtils.getUsedTimeMs(startTimeMs)))
  }

  updatedBlocks
}

15、很难理解的一个东西dropFromMemory,大多数情况性能优化,出现dropFromMemory的身影的时候,当内存不够的时候,尝试释放一部分内存,供其它使用。这个时候是丢弃呢?还是放在磁盘上。比如5000个操作作为Stage,前面4900个做好了,内存满了,如果这个时候需要内存,则会释放一部分内存。这个时候,前面以内存方式形式存储,就丢弃一部分。如果数据是DISK_AND_MEMORY,则可能会转移一部分到磁盘来释放内存。这里的dropFromMemory就是在这样的背景下出来的。

def dropFromMemory(
    blockId: BlockId,
    data: Either[Array[Any]ByteBuffer]): Option[BlockStatus] = {
  dropFromMemory(blockId() => data)
}

如果放在DISK_AND_MEMORY的时候,优先放内存,优先放内存,不够放才会放磁盘,如果以前存储的时候没有说同时可以存储在内存和磁盘中的话,这个时候就会丢弃了,这个时候如果再要,就会重新计算

/**
 * Drop a block from memory, possibly putting it on disk if applicable. Called when the memory
 * store reaches its limit and needs to free up space.
 *
 * If `datais not put on disk, it won't be created.
 *
 * Return the block status if the given block has been updated, else None.
 */
def dropFromMemory(
    blockId: BlockId,
    data: () => Either[Array[Any]ByteBuffer]): Option[BlockStatus] = {

  logInfo(s"Dropping block $blockId from memory")
  val info = blockInfo.get(blockId).orNull

  // If the block has not already been dropped
  if (info != null) {
    info.synchronized {
      // required ? As of now, this will be invoked only for blocks which are ready
      // But in case this changes in future, adding for consistency sake.
      if (!info.waitForReady()) {
        // If we get here, the block write failed.
        logWarning(s"Block $blockId was marked as failure. Nothing to drop")
        return None
      } else if (blockInfo.get(blockId).isEmpty) {
        logWarning(s"Block $blockId was already dropped.")
        return None
      }
      var blockIsUpdated = false
      val level = info.level

      // Drop to disk, if storage level requires
      if (level.useDisk && !diskStore.contains(blockId)) {
        logInfo(s"Writing block $blockId to disk")
        data() match {
          case Left(elements) =>
            diskStore.putArray(blockIdelementslevelreturnValues = false)
          case Right(bytes) =>
            diskStore.putBytes(blockIdbyteslevel)
        }
        blockIsUpdated = true
      }

      // Actually drop from memory store
      val droppedMemorySize =
        if (memoryStore.contains(blockId)) memoryStore.getSize(blockId) else 0L
      val blockIsRemoved = memoryStore.remove(blockId)
      if (blockIsRemoved) {
        blockIsUpdated = true
      else {
        logWarning(s"Block $blockId could not be dropped from memory as it does not exist")
      }

      val status = getCurrentBlockStatus(blockIdinfo)
      if (info.tellMaster) {
        reportBlockStatus(blockIdinfostatusdroppedMemorySize)
      }
      if (!level.useDisk) {
        // The block is completely gone from this node; forget it so we can put() it again later.
        blockInfo.remove(blockId)
      }
      if (blockIsUpdated) {
        return Some(status)
      }
    }
  }
  None
}

private val entries = new LinkedHashMap[BlockId, MemoryEntry](32, 0.75f, true)

王家林老师名片:

中国Spark第一人

新浪微博:http://weibo.com/ilovepains

微信公众号:DT_Spark

博客:http://blog.sina.com.cn/ilovepains

手机:18610086859

QQ:1740415547

邮箱:[email protected]


本文出自 “一枝花傲寒” 博客,谢绝转载!

你可能感兴趣的:(manager,初始化,block)