spark存储体系概览

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

6.1.1 存储体系架构

1)BlockManagerMaster:代理BlockManager与Driver上的BlockManagerMasterEndpoint通信。通信的内容很多,例如:注册BlockManager、更新Block信息、获取Block的位置,删除Executor等。

2)BlockManagerMasterEndpoint:由Driver上的SparkEnv负责创建和注册到Driver的RpcEnv中。主要对各个节点上的BlockManager、BlockManager与Executor的映射关系及Block的位置信息等进行管理

3)BlockManagerSlaveEndpoint,每个Executor或Driver的SparkEnv中都有属于自己的BlockManagerSlaveEndpoint,分别由各自的SparkEnv负责创建和注册到各自的RpcEnv中。BlockManagerSlaveEndpoint将接受BlockManagerMasterEndpoint下发的命令。下发命令很多,例如:删除Block、获取Block状态、获取匹配的BlockId等。

4)SerializerManager:序列化管理器

5)MemoryManager:内存管理器,负责对单个节点上内存的分配和回收

6)MapOutputTracker:map任务输出管理器

7)ShuffleManager:Shuffle管理器

8)BlockTransferService:块传输管理器,主要用于不同阶段的任务之间的Block数据的传输和读写

9)shuffleClient:Shuffle客户端,与BlockTransferService配合使用

10)SecurityManager:安全管理器

11)DiskBlockManager:磁盘块管理器,对磁盘上的文件以及目录的读写操作进行管理

12)BlockInfoManager:块信息管理器,负责对Block的元数据以及锁资源进行管理

13)MemoryStore:内存存储

14)DiskStore:磁盘存储

6.1.2 基本概念

1、BlockManager的唯一标识BlockManagerId

BlockManagerId的提供的方法:

isDriver:当前BlockManager所在的实例是否是Driver,此方法根据executorId的值是否是Driver来判断

writeExternal:将BlockManagerId的所有信息序列化后写到外部二进制中

readExternal:从外部二进制流中读取BlockManagerId的所有信息

2、块的唯一标识

文件系统的文件存储到磁盘上,都是以块为单位写入的,操作系统的块都是以固定大小读写的

在Spark存储体系中,数据的读写也是以块为单位的,只不过这个块并非操作系统的块,而是设计用于Spark存储体系的块。每个Block都有唯一的标识,Spark把这个表示抽象为BlockId.

 

6.5 内存管理器

Spark与Hadoop最重要的区别之一就在于对内存的使用,Hadoop只将内存作为计算资源,而Spark除了将内存作为计算资源之外,还将内存的一部分纳入到存储体系中。Spark使用MemoryManager对存储体系和内存体系计算所使用的内存进行管理。

6.5.1 内存池模型

Spark存储体系的每个存储节点上也不止一个内存池。内存池实质上是对物理内存的逻辑规划,协助Spark任务在运行时合理地使用内存资源。Spark将内存从逻辑上区分为堆内存和堆外内存,称为内存模式。

这里的堆内存并不能与JVM中的Java堆直接画等号,它只是JVM堆内存的一部分,堆外内存则是Spark使用sun.misc.Unsafe的API直接在工作节点的系统内存中开辟的空间,无论哪种内存,都需要一个内存池对内存进行资源管理,抽象类MemoryPool

Spark中一共有两种MemoryPool的具体实现,其中StorageMemoryPool是存储体系中用到的内存池,ExecutionMemoryPool则是计算引擎用到的内存池。

6.5.2 StorageMemoryPool详解

StorageMemoryPool是对用于存储的物理内存的逻辑抽象,通过对存储内存的逻辑管理,提高Spark存储体系对内存的使用效率。

1)acquireMemory  用于给BlockId对应的Block获取numBytes指定大小的内存

     此方法首先计算要申请的内存大小numBytes与空闲空间memoryFree的差值,如果numByteToFree大于0.则说明需要腾出部分Block所占用的内存空,然后调用acquireMemory方法申请获得内存

2)releaseMemory  用于释放内存

3)freeSpaceToShrinkPool  用于释放指定大小的空间,缩小内存池的大小

    如果空闲内存大于等于spaceToFree,那么返回sparkToFree即可,否则需要腾出占用内存的部分Block,以补齐spaceToFree的大小,并返回腾出空间与memoryFree的大小之和

6.5.3 MemoryManager模型

1)maxOnHeapStorageMemory:返回用于存储的最大堆内存,此方法需要子类实现

2)maxOffHeapStorageMemory:返回用于存储的最大堆外内存,此方法需要子类实现

3)setMemorySize:给onHeapStorageMemoryPool和offHeapStorageMemoryPool设置MemoryStore

4)acquireStorageMemory:为存储BlockId对应的Block,从堆内存或堆外内存获取所需大小(即numBytes)

5)acquireUnrollMemory:为展开BlockId对应的Block,从堆内存或堆外内存获取所需大小(即numBytes)

6)releaseStorageMemory:从堆内存或堆外内存释放指定大小

7)releaseAllStorageMemory:从堆内存及堆外内存释放所有内存

8)releaseUnrollMemory:释放指定大小的展开内存

9)storageMemoryUsed:onHeapStorageMemoryPool与offHeapStorageMemoryPool中一起占用的存储内存

6.5.4 UnifiedMemoryManager详解

UnifiedMemoryManager提供了统一的存储管理机制,即Spark应用程序在运行期的存储内存和执行内存将共享统一的内存空间,可以动态调节两块内存的空间大小。

UnifiedMemoryManager在MemoryManager的内存模型之上,将计算内存和存储内存之间的边界修改为“软”边界,即任何一方可以向另一方借用空闲的内存。

属性:

1)conf

2)maxHeapMemory

3)onHeapStorageRegionSize

4)numCores

除了继承自MemoryManager的方法外,其特有的方法有:

1)maxOnHeapStorageMemory:返回用于存储的最大堆内存

2)maxOffHeapStorageMemory:返回用于存储的最大堆外内存

3)acquireStorageMemory:为存储BlockId对应的Block,从堆内存或堆外内存获取所需大小(numBytes)的内存

4)acquireUnrollMemory:为展开BlockId对应的Block,从堆内存或堆外内存获取所需大小(即numBytes)的内存,此方法实际代理调用了acquireStorageMemory

 

6.6  内存存储MemoryStore

MemoryStore负责将Block存储到内存,Spark通过广播数据、RDD、Shuffle数据存储到内存,减少了对磁盘I/O的依赖,提高了读写效率

6.6.1  MemoryStore的内存模型

整个MemoryStore的存储分为三块:

1、一块是MemoryStore的entries属性持有的很多MemoryEntry所占据的内存blocksMemoryUsed;

2、一块是onHeapUnrollMemoryMap或offHeapUnrollMemoryMap中使用展开方式占用的内存currentUnrollMemory

3、blocksMemoryUsed和currentUnrollMemory的空间之和是已经使用的空间,用memoryUsed表示。

6.6.2 MemoryStore所提供的方法

memoryStore提供了很多方法,便于对Block数据的存储和读取

1)getSize  此方法用于获取BlockId对应MemoryEntry(即Block的内存形式)所占用的大小

2)putBytes  此方法将BlockId对应的Block(已经封装为ChunkedByteBuffer)写入内存

3)reserveUnrollMemoryForThisTask 此方法用于为展开尝试执行任务给定的Block,保留指定内存模式上指定大小的内存

4)releaseUnrollMemoryForThisTask 此方法用于释放任务尝试线程占用的内存

5)putIteratorAsValues  此方法将BlockId对应的Block(已经转换为Iterator)写入内存。有时候放入内存的Block很大,所以一次性将此对象写入内存可能引发OOM,为了避免这种情况发生,首先需要将Block转换为Iterator,然后渐进式地展开此Iterator,并且周期性的检查是否有足够的展开内存。

6)putIteratorAsBytes  此方法以序列化的字节数组方式,将BlockId对应的Block写入内存

7)getBytes 此方法从内存中读取BlockId对应的Block(已经封装为ChunkedByteBuffer),只能获取序列化的Block

8)getValues   此方法用于从内存中读取BlockId对应的Block(已经封装为Iterator)  只能读取没有序列化的Block

9)remove  此方法用于从内存中移除BlockId对应的Block

10)clear  此方法用于清理MemoryStore

11)evictBlocksToFreeSpace  此方法用于驱逐Block,以便释放一些空间来存储新的Block\

       不应该对有线程正在读取或写入的Block进行驱逐,只能驱逐那些没有被其他线程读或写的Block

12)contains   此方法用于判断本地MemoryStore中是否包含给定BlockId所对应的Block文件

 

6.7  块管理器BlockManager

BlockManager运行在每个节点上(包括Driver和Executor),提供对本地或远端节点上的内存、磁盘及堆外内存中Block的管理。存储体系狭义上来说值得就是BlockManager,但从广义上来说,则包括整个Spark集群中的各个BlockManager、BlockInfoManager、DiskBlockManager、DiskStore、MemoryManager、MemoryStore、对集群中的所有BlockManager进行管理的BlockManagerMaster及各个节点上对外提供Block上传和下载服务的BlockTransferService.

6.7.1 BlockManager初始化

每个Driver或Executor在创建自身的SparkEnv时都会创建BlockManager。BlockManager只有在其initialize方法被调用后才能发挥作用。

6.7.2 BlockManager提供的方法

1、register  此方法用于向BlockManagerMaster重新注册BlockManager,并向BlockManagerMaster报告所有的Block信息

2、getLocalBytes  此方法用于从存储体系中获取BlockId所对应的BlockId的数据,并封装为ChunkedByteBuffer

3、getBlockData  此方法用于获取本地的Block的数据

4、putBytes  用于写入Block数据,需要首先介绍doPut.doPut用于执行Block的写入

5、putBlockData  此方法用于将Block数据写入本地

6、getStatus  此方法用于获取Block的状态

7、getMatchingBlockIds  此方法用于获取匹配过滤器条件的BlockId的序列

8、getLocalValues  此方法用于从本地的BlockManager中获取Block的数据

9、getRemoteBytes  该方法的作用为从远端的BlockManager以序列化的字节形式获取Block数据

10、get  此方法用于优先从本地获取Block数据,当本地获取不到所需的Block数据时,再从远端获取Block数据

11、downgradeLock  此方法将当前线程持有的Block的写锁降级为读锁

12、releaseLock  此方法用于当前线程对持有的Block的锁进行释放

13、registerTask  此方法用于将任务尝试线程注册到BlockInfoManager

14、releaseAllLockForTask  此方法用于任务尝试线程对持有的所有Block的锁进行释放

15、getOrElseUpdate   此方法用于获取Block

16、putIterator  此方法用于将Block数据写入存储体系

17、getDiskWriter  此方法用于创建并获取DiskBlockObjectWriter 通过DiskBlockObjectWriter可以跳过对DiskStore的使用,直接将数据写入磁盘

18、putSingle  此方法的作用为获取由单个对象组成的Block

19、putSingle  此方法用于将由单个对象组成的Block写入存储体系。

20、dropFromMemory  此方法用于从内存中删除Block  当Block的存储级别允许写入磁盘时,Block将被写入磁盘

21、removeBlock 此方法的作用用于删除指定的Block

22、removeRdd  此方法的作用为移除属于指定的RDD的所有Block

6.8 BlockManagerMaster对BlockManager的管理

BlockManagerMaster的作用是对存在于Executor或Driver上的BlockManager进行统一管理。Executor与Driver关于BlockManager的交互都依赖于BlockManagerMaster,比如Executor需要向Driver发送注册BlockManager、更新Executor上Block的最新信息、询问所需要Block目前所在的位置及当Executor运行结束需要将此Executor移除等。

我们知道Driver上的BlockManagerMaster会实例化并且注册BlockManagerMasterEndpoint。无论是Driver还是Executor,它们的BlockManagerMaster的driverEndpoint属性都持有BlockManagerMasterEndpoint的RpcEndpointRef。无论是Driver还是Executor,每个BlockManager都拥有自己的BlockManagerSlaveEndpoint,且BlockManager的slaveEndpoint属性保存着各自的RpcEndpointRef。BlockManagerMasterEndpoint负责发送消息,BlockManagerSlaveEndpoint负责消息的接收与处理,BlockManagerSlaveEndpoint则接收BlockManagerMasterEndpoint下发的命令。

6.8.1  BlockManagerMaster的职责

BlockManagerMaster负责发送各种与存储体系相关的信息

以RegisterBlockManager为例:注册BlockManager的实质是向BlockManagerMasterEndpoint发送RegisterBlockManager消息

 

6.8.2 BlockManagerMasterEndpoint

BlockManagerMasterEndpoint接收Driver或Executor上BlockManagerMaster发送的消息,对所有的BlockManager进行统一管理。

BlockManagerMasterEndpoint中定义了一些管理BlockManager的属性:

1、blockManagerInfo:BlockManagerId与BlockManagerInfo之间的映射关系

2、blockManagerIdByExecutor:Executor ID与BlockManagerId之间的映射关系

3、blockLocation:BlockId与存储了此BlockId对应Block的BlockManager的BlockManagerId之间的一对多关系映射

4、topologyMapper:对集群所有节点的拓扑结构的映射

以RegisterBlockManager为例:BlockManagerMasterEndpoint在接收到RegisterBlockManager消息后,将调用register方法。

 

6.8.3 BlockManagerSlaveEndpoint

BlockManagerSlaveEndpoint用于接收BlockManagerMasterEndpoint的命令并执行相应的操作。

BlockManagerSlaveEndpoint也重写了receiverAndReply方法

receiveAndReply方法支持接收以下方法:

1、RemoveBlock

2、RemoveRdd

3、RemoveShuffle

4、RemoveBroadcast

5、GetBlockStatus

6、getMatchingBlockIds

7、TriggerThreadDump

6.9 Block传输服务

BlockTansferService是BlockManager的子组件之一。抽象类BlockTransferService有两个实现:用于测试的MockBlockTransferService以NettyBlockTransferService。我们知道BlockManager实际采用了NettyBlockTransferService提供的Block传输服务。

6.9.1 初始化NettyBlockTransferService

6.9.2 NettyBlockRpcServer详解

你可能感兴趣的:(spark存储体系概览)