Spark源码阅读03-Spark存储原理之存储分析

def registerOrLookupEndpoint(name: String, endpointCreator: => RpcEndpoint): RpcEndpointRef = {

//创建远程数据传输服务,使用Netty方式

val blockTransferService =

new NettyBlockTransferService(conf, securityManager, bindAddress, advertiseAddress,

blockManagerPort, numUsableCores)

//创建blockManagerMaster,如果是Driver端在blockManagerMaster内部则创建终端点BlockManagerMasterEndpoint

//如果是Executor,则创建BlockManagerMasterEndpoint的引用

val blockManagerMaster = new BlockManagerMaster(registerOrLookupEndpoint(

BlockManagerMaster.DRIVER_ENDPOINT_NAME,

new BlockManagerMasterEndpoint(rpcEnv, isLocal, conf, listenerBus)),

conf, isDriver)

//创建blockManager,如果是Driver端包含blockManagerMaster,如果是executor包含的是blockManagerMaster

//的引用,另外blockManager包含了远程数据传输服务,当BlockManager调用initialize()方法才生效

val blockManager = new BlockManager(executorId, rpcEnv, blockManagerMaster,

serializerManager, conf, memoryManager, mapOutputTracker, shuffleManager,

blockTransferService, securityManager, numUsableCores)

}

其中BlockManager调用initialize()方法的初始化如下:

def initialize(appId: String): Unit = {

//在Executor中启动远程数据传输服务,根据配置启动传输服务器blockTransferService,

//该服务器启动后等待其他节点发送请求消息

blockTransferService.init(this)

shuffleClient.init(appId)

blockReplicationPolicy = {

val priorityClass = conf.get(

“spark.storage.replication.policy”, classOf[RandomBlockReplicationPolicy].getName)

val clazz = Utils.classForName(priorityClass)

val ret = clazz.newInstance.asInstanceOf[BlockReplicationPolicy]

logInfo(s"Using $priorityClass for block replication policy")

ret

}

//获取blockManager编号

val id =

BlockManagerId(executorId, blockTransferService.hostName, blockTransferService.port, None)

val idFromMaster = master.registerBlockManager(

id,

maxOnHeapMemory,

maxOffHeapMemory,

slaveEndpoint)

blockManagerId = if (idFromMaster != null) idFromMaster else id

//获取shuffle服务编号,如果启动外部shuffle服务,则加入外部Shuffle服务端口信息,

//否则使用使用blockManager编号

shuffleServerId = if (externalShuffleServiceEnabled) {

logInfo(s"external shuffle service port = $externalShuffleServicePort")

BlockManagerId(executorId, blockTransferService.hostName, externalShuffleServicePort)

} else {

blockManagerId

}

//如果外部shuffle服务启动并且为executor节点,则注册为外部shuffle服务

if (externalShuffleServiceEnabled && !blockManagerId.isDriver) {

registerWithExternalShuffleServer()

}

logInfo(s"Initialized BlockManager: $blockManagerId")

}

(2)写入、 更新或删除数据完毕后, 发送数据块的最新状态消息UpdateBlockinfo给BlockManagerMasterEndpoint终端点, 由其更新数据块的元数据。 该终端点的元数据存放在BlockManagerMasterEndpoint的3个HashMap中, 分别如下:

class BlockManagerMasterEndpoint(override val rpcEnv: RpcEnv,val isLocal: Boolean,conf: SparkConf,listenerBus: LiveListenerBus)

extends ThreadSafeRpcEndpoint with Logging {

//该HashMap中存放了BlockManagerId与BlockManagerInfo的对应,其中BlockManagerInfo

//包含了executor的内存使用情况、数据块的使用情况、已被缓存的数据块和executor终端点的引用

private val blockManagerInfo = new mutable.HashMap[BlockManagerId, BlockManagerInfo]

//该HashMap存放了BlockManagerId和executorId对应列表

private val blockManagerIdByExecutor = new mutable.HashMap[String, BlockManagerId]

//该HashMap存放了BlockManagerId和BlockId序列所对应的列表,原因在于一个数据块可能存储

//多个副本,保存在多个executor中

private val blockLocations = new JHashMap[BlockId, mutable.HashSet[BlockManagerId]]

}

(3)应用程序数据存储后, 在获取远程节点数据、 获取RDD执行的首选位置等操作时需要根据数据块的编号查询数据块所处的位置, 此时发送 GetLocations 或GetLocationsMultipleBlocklds等消息给BlockManagerMasterEndpoint终端点,通过对元数据的查询获取数据块的位置信息。

代码实现如下:

private def getLocations(blockId: BlockId): Seq[BlockManagerId] = {

//根据blockId判断是否包含数据块,如果包含,则返回其对应的BlockManagerId序列

if (blockLocations.containsKey(blockId)) blockLocations.get(blockId).toSeq

else Seq.empty

}

(4)Spark提供删除RDD、 数据块和广播变量等方式。 当数据需要删除时, 提交删除消息给BlockManagerSlaveEndpoint 终端点, 在该终端点发起删除操作, 删除操作一方面需要删除Driver端元数据信息,另一方面需要发送消息通知Executor,删除对应的物理数据。下面以RDD的unpersistRDD方法描述其删除过程。类调用关系图如下:

在这里插入图片描述

首先, 在SparkConext中调用unpersistRDD方法, 在该方法中发送removeRdd 消息给 BlockManagerMasterEndpoint终端点;然后, 该终端点接收到消息时, 从blockLocations列表中找出该ROD对应的数据存在BlockManagerld 列表, 查询完毕后, 更新blockLocations和 blockManagerlnfo两个数据块元数据列表; 然后, 把获取的BlockManagerld列表, 发送消息给所在BlockManagerSlaveEndpoint 终端点, 通知其删除该 Executor上的RDD, 删除时调用 BlockManager的removeRdd方法, 删除在Executor上RDD所对应的数据块。 其中在 BlockManagerMasterEndpoint终端点的removeRdd代码如下:

private def removeRdd(rddId: Int): Future[

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值