6、Storage
Storage模块负责管理Spark计算过程中产生的数据,包括基于Disk的和基于Memory的。
用户编程时候cache将数据持久化,持久化的动作都是由Storage模块完成的,包括Shuffle过程中的数据,都是Storage模块管理的。
RDD实现的是用户逻辑,而Storage管理用户的数据。在Driver端和Executor端,都会有Storage模块。
6.1、Storage整体架构
Storage模块采用的是Master/Slave的架构。
Master负责整个Application的Block的元数据信息的管理和维护。
Slave需要将Block的更新等状态上报到Master,同时接收Master的命令,比如删除一个RDD、Shuffle相关的数据或者广播变量。
Master与Slave之间通过AKKA消息传递机制进行通信。
下图为Storage模块架构图:
在SparkContext创建时,它会创建Driver端的SparkEnv,而SparkEnv会创建
BlockManager,BlockManager创建的时候会持有一个BlockManagerMaster。BlockManagerMaster会把请求转发给BlockManagerMasterActor来完成元数据的管理和维护。
而在Executor端,也存在一个BlockManager,它也会持有一个BlockManagerMaster,只不过BlockManagerMaster会持有一个Driver端BlockManagerMasterActor的Reference,因此Executor端的BlockManager就能通过这个Actor的Reference将Block的信息上报给Master。
BlockManager本身还持有一个BlockManagerSlaveActor,而这个Slave的Actor还会被上报到Master。Master会持有这个Slave Actor的Reference,并通过这个Reference向Slave发送一些命令,比如删除Slave上的RDD、Shuffle相关的数据或者是广播变量。
Master和Slave之间并没有专门的心跳,而是通过Driver和Executor之间的心跳来间接完成的。
Master持有整个Application的Block的元数据信息,包括Block所在的位置,Block所占的存储空间大小(含3种级别:内存、Disk和Tackyon)。
6.2、Partition与Block
BlcokManager是Storage模块与其他模块交互的最主要的类,它提供了读和写Block的接口。
这里的Block实际上就对应了RDD中提到的Partition,每一个Partiton都会对应一个Block。
每个Block由唯一的Block ID标识,格式rdd_ + rddid + partitionid。
下图为:RDD的partition和block的逻辑关系图
BlockManager会运行在Driver和每一个Executor上。
运行在Driver上的BlockManager负责整个Application的Block的管理工作。
运行在Executor上的BlockManager负责管理该Executor上的Block,并且向Driver的BlockManager汇报Block的信息和接收来自它的命令。
6.3、存储级别
存储级别,对用户来说是RDD相关的持久化和缓存。
在每个节点都将RDD的partition的数据保存在内存中,后续的计算将会变得非常快(通常会10倍以上)。可以说,缓存是Spark构建迭代式算法和快速交互式查询的关键。
用户可以直接调用persus()或者cache()来标记一个RDD需要持久化,cache()是使用默认存储级别的快捷方式。
只有触发了一个Action后,计算才会提交到集群开始真正的运算。因此RDD只有经过一次Action后,才能将RDD缓存到内存中以供以后的计算使用。
用户可以设置StorageLevel来设置需要的存储级别。不同的存储级别可以选择持久化数据到Disk、Memory、Tachyon。
下图为Storage模块支持的存储级别: