简单来讲,Spark存储体系是各个Driver与Executor实例中的BlockManager所组成的;但是从一个整体来看,把各个节点的BlockManager看成存储体系的一部分,那存储体系就有了更多衍生的内容,比如块传输服务、map任务输出跟踪器、Shuffle管理器等。

1 存储体系架构

先用下图从整体上表示存储体系架构

spark package spark package management_Boo

根据上图可以看到,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的状态信息。