简单来讲,Spark存储体系是各个Driver与Executor实例中的BlockManager所组成的;但是从一个整体来看,把各个节点的BlockManager看成存储体系的一部分,那存储体系就有了更多衍生的内容,比如块传输服务、map任务输出跟踪器、Shuffle管理器等。
1 存储体系架构
先用下图从整体上表示存储体系架构
根据上图可以看到,BlockManager依托于很多组件的服务,这些组件包括以下几项:
- 1)BlockManagerMaster:代理BlockManager与Driver上的BlockManagerMasterEndpoint通信。记号①表示Executor节点上的BlockManager通过BockManagerMaster与BlockManagerMasterEndpoint进行通信,记号②表示Driver节点上的BlockManager通过BlockManagerMaster与BlockManagerMasterEndpoint进行通信。这些通信的内容有很多,例如,注册BlockManager、更新Block信息、获取Block的位置(即Block所在的BlockManager)、删除Executor等。BlockManagerMaster之所以能够和BlockManagerMasterEndpoint通信,是因为它持有了BlockManagerMasterEndpoint的RpcEndpointRef。
- 2)BlockManagerMasterEndpoint:由Driver上的SparkEnv负责创建和注册到Driver的RpcEnv中。BlockManagerMasterEndpoint只存在于Driver的SparkEnv中,Driver或Executor上BlockManagerMaster的driverEndpoint属性将持有BlockManagerMasterEndpoint的RpcEndpointRef。BlockManagerMasterEndpoint主要对各个节点上的BlockManager、BlockManager与Executor的映射关系及Block位置信息(即Block所在的BlockManager)等进行管理。
- 3)BlockManagerSlaveEndpoint:每个Executor或Driver的SparkEnv中都有属于自己的BlockManagerSlaveEndpoint,分别由各自的SparkEnv负责创建和注册到各自的RpcEnv中。Driver或Executor都存在各自的BlockManagerSlaveEndpoint,并由各自BlockManager的slaveEndpoint属性持有各自BlockManagerSlaveEndpoint下发的命令。记号③表示BlockManagerMasterEndpoint向Driver节点上的BlockManagerSlaveEndpoint下发命令,记号④表示BlockManagerMasterEndpoint向Executor节点上的BlockManagerSlaveEndpoint下发命令。例如,删除Block、获取Block状态、获取匹配的BlockId等。
- 4)SerializerManager:序列化管理器
- 5)MemoryManager:内存管理器。负责对单个节点上内存的分配与回收
- 6)MapOutPutTracker:map任务输出跟踪器。
- 7)ShuffleManager:Shuffle管理器
- 8)BlockTransferService:块传输服务。此组件也与Shuffle相关联,主要用于不同阶段的任务之间的Block数据的传输与读写。
- 9)shuffleClinet:Shuffle的客户端。与BlockTransferService配合使用。记号⑤表示Executor上的shuffleClient通过Driver上的BlockTransferService提供的服务上传和下载Block,记号⑥表示Driver上的shuffleClient通过Executor上的BlockTransferService提供的服务上传和下载Block。此外,不同Executor节点上的BlockTransferService和shuffleClient之间也可以互相上传、下载Block。
- 10)SecurityManager:安全管理器
- 11)DiskBlockManager:磁盘块管理器。对磁盘上的文件及目录的读写操作进行管理
- 12)BlockInfoManager:块信息管理器。负责对Block的元数据及锁资源进行管理
- 13)MemoryStore:内存存储。依赖于MemoryManager,负责对Block的内存存在
- 14)DiskStore:磁盘存储。依赖于DiskBlockManager,负责对Block的磁盘存储
2 基本概念
2.1 BlockManager的唯一标识BlockManagerId
Driver或者Executor中有任务执行的环境SparkEnv,每个SparkEnv中都有BlockManager,这些BlockManager位于不同的节点和实例上。BlockManager之间需要通过RpcEnv、shuffleClient及BlockTransferService相互通信,每个BlockManager都有其在Spark集群内的唯一标识BlockManagerId。
Spark通过BlockManagerId中的host、port、executorId等信息来区分BlockManager。其属性有:
- host_:主机域名或IP
- port_:此端口实际使用了BlockManager中的BlockTransferService对外服务的端口
- executorId_:当前BlockManager所在的实例ID。如果实例是Driver,那么ID为driver,否则由Master负责给各个Executor分配,ID格式为app-日期格式字符串
BlockManagerId中的方法:
- executorId:返回executorId_的值
- hostPort:返回host:port格式的字符串
- host:返回host_的值
- port:返回port_的值
- topologyInfo:返回topologyInfo_的值
- isDriver:当前BlockManager所在的实例是否是Driver
- writeExternal:将BlockManagerId的所有信息序列化后写到外部二进制流中
- readExternal:从外部二进制流中读取BlockManagerId的所有信息。
2.2 块的唯一标识BlockId
在Spark的存储体系中,数据的读写是以块为单位,每个Block都有唯一的标识,Spark把这个标识抽象为BlockId。
//org.apache.spark.storage.BlockId
@DeveloperApi
sealed abstract class BlockId {
def name: String
def asRDDId: Option[RDDBlockId] = if (isRDD) Some(asInstanceOf[RDDBlockId]) else None
def isRDD: Boolean = isInstanceOf[RDDBlockId]
def isShuffle: Boolean = isInstanceOf[ShuffleBlockId]
def isBroadcast: Boolean = isInstanceOf[BroadcastBlockId]
override def toString: String = name
override def hashCode: Int = name.hashCode
override def equals(other: Any): Boolean = other match {
case o: BlockId => getClass == o.getClass && name.equals(o.name)
case _ => false
}
}
根据上述代码,BlockId中定义了以下方法:
- name:Block全局唯一的标识名
- isRDD:当前BlockId是否是RDDBlockId
- asRDDId:将当前BlockId转换为RDDBlockId。如果当前BlockId是RDDBlockId,则转换为RDDBlockId,否则返回None
- isShuffle:当前BlockId是否是ShuffleBlockId
- isBroadcast:当前BlockId是否是BroadcastBlockId
2.3 块信息BlockInfo
BlockInfo用于描述块元数据信息,包括存储级别、Block类型、大小、锁信息等
2.4 存储级别StorageLevel
Spark的存储体系包括磁盘存储与内存存储,而Spark将内存又分为堆外内存和堆内存。有些数据块本身支持序列化及反序列化,有些数据块还支持备份与复制。Spark存储体系将以上这些数据块的不同特性抽象为存储级别StorageLevel。
2.5 BlockResult
BlockResult用于封装从本地的BlockManager中获取的Block数据及与Block相关联的度量数据。
2.6 BlockStatus
样例类BlockStatus用于封装Block的状态信息。