RDD是核心
Spark的计算全部基于接口RDD,RDD包括一组partitions和几个接口方法。
- spark的计算过程实质是对一个RDD实例进行处理生成另一个RDD实例
- 计算过程会生成base RDD、transformation RDD、action RDD、cache RDD几类RDD
- 输入算子从hdfs读取blocks生成一个base RDD,每个block生成一个partition
- 转换算子对base RDD内的partitions内的数据进行过滤生成一个filter RDD,也是transformation RDD
- 缓存算子对RDD缓存生成cache RDD
- 最后对RDD进行collect等操作时生成action RDD
- lineage实现容错性,并且更高效
lineage是指记录了RDD间的partitions的依赖关系,如果其中一个partition的数据丢失,则可以根据依赖关系,从头到尾再计算一遍,这样哪个partition出错才重新计算哪个,节省时间。 - 延时调度,更加高效。
只有遇到需要生成action RDD的算子时,才会真正开始计算和调度 - 窄依赖和宽依赖
- 窄依赖:如果一个算子的源RDD的partition和生成的RDD内的partition是1对1的关系,则此算子的源RDD和生成的RDD间的依赖关系是窄依赖。包括map、union等。
- 宽依赖:如果源RDD的partitions和生成的RDD的partitions是1对多的关系,则为宽依赖。包括groupBy、没有做预分区(co-partition)的join等。
- 根据宽依赖划分stage
从后往前根据RDD间的partition的依赖关系,遇到宽依赖则从此算子开始到前一个宽依赖的算子之前的算子结束,为一个stage - partition为计算的最小单位
- 不需物化,迭代进行
窄依赖与宽依赖
- 窄依赖在计算时更加节能高效
窄依赖允许在单节点上流水操作,源RDD的一个partition完成即可对此partition进行计算,无需shuffle更高效。
宽依赖必须源RDD的所有partitions都已经准备好后,再对这些源partitions进行shuffle - 窄依赖在故障恢复时,更加节能高效
如果算子是窄依赖,其中一个partition计算失败,只需将其父partition重新计算一遍
如果算子中有宽依赖则宽依赖则需将多个partition进行重新计算。
Spark Application的组成
- 一个Spark Applicaiton包括一个driver和多个executors
- dirver:运行main函数和生成SparkContext的程序
- executor:在集群的节点上对某个应用启动一个进程,执行计算任务
- cluster manager是调度计算任务、为任务分配资源的,比如yarn
- Job:和action算子是一一对应的,一个action算子会生成一个Job
- Task:一个Job有多个算子,每个算子作用在一个partition上形成一个Task。
- Stage:宽依赖的算子必须等待上一算子的所有Task都执行完成,所有源partition都以就绪后,才能开始执行,这时就形成了一个stage。当前stage必须等待上一stage执行完毕,才能开始执行,是串行的。一个stage内不同partition的Task间可以多partition并行执行的。