Spark中的Cache, Shuffle-output, 以及Broadcast的实现都是基于BlockManager来实现,BlockManager提供了数据存储[内存/文件存储]接口。BlockManager是通过Block来组织和管理数据的,块的唯一标识是BlockId;BlockManager控制块数据的写入和读取,数据的表达方式是ManagerBuffer;另外BlockManager需要对Block元信息进行管理,元信息的维护是通过BlockInfo来进行的,本节我们就来看一下这三部分的实现方式。
BlockId
整体架构
在Spark的存储体系中,数据的读写是以块为单位,也就是说Block是Spark存储的基本单位,这里的Block和Hdfs的Block是不一样的,HDFS中是对大文件进行分Block进行存储,Block大小是由dfs.blocksize
决定的;而Spark中的Block是用户的操作单位,一个Block对应一块有组织的内存,一个完整的文件或文件的区间端,并没有固定每个Block大小的做法。
每个块都有唯一的标识,Spark把这个标识抽象为BlockId。BlockId本质上是一个字符串,但是在Spark中将它保证为"一组"case类,这些类的不同本质是BlockID这个命名字符串的不同,从而可以通过BlockID这个字符串来区别BlockId,继承体系如下:
可以看出,块主要是用来服务Shuffle,RDD,TaskResult,Broadcast以及Temp文件使用,命名规则如下:
- RDDBlockId是从数据源读取到的初始RDD或者transform得到的RDD:
"rdd_" + rddId + "_" + splitIndex
- Shuffle过程中会产生shuffleBlock,以及数据Block和索引Block文件,分别命名如下:
- ShuffleBlockId:
"shuffle_" + shuffleId + "_" + mapId + "_" + reduceId
- ShuffleDataBlockId:
"shuffle_" + shuffleId + "_" + mapId + "_" + reduceId + ".data"
- ShuffleIndexBlockId:
"shuffle_" + shuffleId + "_" + mapId + "_" + reduceId + ".index"
- ShuffleBlockId:
- BroadcastBlockId中使用的Block命名:
"broadcast_" + broadcastId + (if (field == "") "" else "_" + field)
- TaskResultBlockId是ResultTask中返回结果使用的Block命名:
"taskresult_" + taskId
- Tmp相关的Block是中间文件:
- TempShuffleBlockId是shuffle中的中间文件:
"temp_shuffle_" + id
- TempLocalBlockId是本地文件,DiskBlockManager中会使用到,命名:
"temp_local_" + id
- TempShuffleBlockId是shuffle中的中间文件:
- TestBlockId供测试使用,命名
"test_" + id
源码分析
先看下BlockId的抽象类定义,name
是标识,不同的子类有不同的命名规范,另外就是判断当前BlockId是否为RDD,Shuffle以及BroadCast的方法。
sealed abstract class BlockId {
/** A globally unique identifier for this Block. Can be used for ser/de. */
// 唯一名字,由后续子类进行实现,各种Block有不同的命名规范
def name: String
// convenience methods
def asRDDId: Option[RDDBlockId] = if (isRDD) Some(asInstanceOf[RDDBlockId]) else None
/** 判断是否属于RDD,Shuffle,Broadcast */
def isRDD: Boolean = isInstanceOf[RDDBlockId]
def isShuffle: Boolean = {
(isInstanceOf[ShuffleBlockId] || isInstanceOf[ShuffleBlockBatchId] ||
isInstanceOf[ShuffleDataBlockId] || isInstanceOf[ShuffleIndexBlockId])
}
def isBroadcast: