spark RRD 依赖关系:
窄依赖:每个父RRD的分区至多被一个子RDD的分区使用,协同划分,分区一一对应。
宽依赖(ShuffleDependecy):多个子RDD的分区依赖一个父RDD的分区。宽依赖需要所有的父RDD分区数据可用。宽依赖会重新分区。
宽依赖操作会有一个可选参数(手动设置分区数)。
宽依赖对应的RDD实现是ShuffledRDD,其compute(~)方法:获取Reader,读取分区数据做reduce,结果作为当前RDD的数据。
ShuffleMapStage的task对其ShuffleDependecy._rdd做shuffle操作(相当于mapreduce的map操作),RDD数据根据partitioner重新分区,写入到分区文件。
Stage(id, rdd, rdd.partitions.length, parents, firstJobId, callSite)其有两个实现类:
ResultStage =》 是action操作触发,每个job只有一个,rdd是操作action的RDD,func是action函数
ShuffleMapStage =》宽依赖时触发,rdd是操作shuffle的RDD(== shuffleDep._rdd),shuffleDep就是当前ShuffleDependency;
shuffleDep._rdd根据partitioner重新分区,做shuffle,把数据写入到对应的分区分区文件,当前stage task结束
属性:ShuffleMapStage.outputLocs = Array.fill[List[MapStatus]](numPartitions)(Nil) #保存每个task运行状态,默认值nil
spark job stage是依据宽依赖(ShuffleDependences)作为分界线来划分。
stages按顺序运行,通过action操作启动job,初始化finalStage(对应的是action操作),通过getParentStages逆向递归得到入口stage,开始运行;
后续stage启动时taskScheduler和taskSetManager通过rpc调用dagSchedule来触发事件来执行的
案例:
def main(args: Array[String]): Unit = { val conf =new SparkConf().setAppName("SUM"); conf.setMaster("local") val size=1024*1024*1024; val sc=new SparkContext(conf); val paralleRDD=sc.parallelize( 0 to 100) val mapRDD = paralleRDD.map(x => (x,1)) val reduceRDD =mapRDD.reduceByKey((x,y) => x+y,10) val d=reduceRDD.keys.count() println(d); while(true){ }
DAG图:
1,reduceByKey做shuffle操作,reduceByKey操作返回的是shuffleRDD
2,shuffleRDD的依赖是shuffleDependence
3,job依据shuffleDependence拆分成两个stage(stage0:ShuffleMapStage,stage1:ResultStage),stage按顺序执行
4,ShuffleMapStage对应的ShuflleMapTask;ShuflleMapTask处理shuffleDependence,shuffleDependence._rdd(shuffleRDD的父RDD)
shuffleDependence._rdd血缘惰性加载,逆向回溯,从parallelize开始,顺序加载获得数据。
通过partitoner对shuffleDependence._rdd重新分区,做shuffle,把数据写入到对应的分区分区文件,当前stage task结束
5,ShuffleMapStage运行完毕,会触发DAG调用下个一个stage ==》stage1(ResultStage)
6,stage1处理RDD数据,RDD血缘惰性加载,逆向回溯,调用shuffleRDD.compute(~)读取分区文件数据(stage0处理好的)
对分区数据做reduce操作获取shuffleRDD的数据,再正向RDD数据传递计算,得到stage1的RDD数据。
7,对stage1的RDD数据做Action操作,获得结果。