SparkContext与DAGScheduler
走读SparkContext初始化及DAGScheduler划分stage并提交任务代码,主要涉及在Driver进程中做的事。
SparkContext初始化
初始化环境,启动各组件:
- SparkEnv在createFromSystemProperties方法中初始化其中的组件
- cache: Cache,
- serializer: Serializer,
- closureSerializer: Serializer,
- cacheTracker: CacheTracker,
- mapOutputTracker: MapOutputTracker,
- shuffleFetcher: ShuffleFetcher,
- shuffleManager: ShuffleManager
- Broadcast
- Scheduler(DAGSchedular)
此版本中Schedular只有LocalScheduler和MesosScheduler两种调度器
Scheduler初始化
private var scheduler: Scheduler = {
// Regular expression used for local[N] master format
val LOCAL_N_REGEX = """local\[([0-9]+)\]""".r
// Regular expression for local[N, maxRetries], used in tests with failing tasks
val LOCAL_N_FAILURES_REGEX = """local\[([0-9]+),([0-9]+)\]""".r
master match {
case "local" =>
new LocalScheduler(1, 0)
case LOCAL_N_REGEX(threads) =>
new LocalScheduler(threads.toInt, 0)
case LOCAL_N_FAILURES_REGEX(threads, maxFailures) =>
new LocalScheduler(threads.toInt, maxFailures.toInt)
case _ =>
MesosNativeLibrary.load()
new MesosScheduler(this, master, frameworkName)
}
}
scheduler.start()
LocalScheduler初始化
通过Executors.newFixedThreadPool
生成一个线程池,start
方法为空
MesosScheduler初始化
todo
创建rdd及任务提交
创建rdd
最底层创建rdd的方法:
- parallelize => ParallelCollection
- hadoopRDD => HadoopRDD
- hadoopFile => HadoopRDD
- newAPIHadoopFile => NewHadoopRDD
所有rdd继承抽象类RDD,其构造函数如下:
abstract class RDD[T: ClassManifest](@transient sc: SparkContext)
可以看到,每个rdd都依赖SparkContext(sc),而以上创建rdd的方法在初始化rdd时会将当前sc注入rdd;rdd通过transform算子互相依赖,这个sc可以被rdd形成dag的最后一个rdd引用到,在action算子中调用sc的SparkContext.runJob
方法进行任务触发。
SparkContext.runJob
方法调用Scheduler的Scheduler.runJob
方法进行stage划分及任务提交。
stage提交
DAGScheduler.runJob
方法中执行stage划分、任务提交、任务调度
stage划分
主要涉及的方法
- newStage
- getParentStages
- getShuffleMapStage
newStage方法作为stage划分入口,初始时DAGScheduler调用该方法生成最后一个stage(从后向前逆向遍历rdd依赖形成的dag)。
实际遍历dag是由getParentStages进行的,遍历方式为递归实现的dfs,每访问一个rdd,其依赖类型为ShuffleDependency,会触发stage划分。
stage划分由getShuffleMapStage执行,在stage划分阶段,该方法内部调用newStage生成新stage返回给getParentStages,再返回给上一层newStage方法,作为依赖注入上一层newStage方法实例化的Stage对象,从而构建Stage依赖链,完成stage划分。其创建的stage会被存入DAGScheduler的shuffleToMapStage,一个HashMap
由于stage是在ShuffleDependency处划分,除了最后一个stage外,newStage方法中都会将shuffle注册到MapOutputTracker;另外rdd也在newStage方法中注册到CacheTracker。
Stage对象中保存的信息:
class Stage(
val id: Int, // stage id
val rdd: RDD[_], // 当前stage最后一个rdd
val shuffleDep: Option[ShuffleDependency[_,_,_]], // 当前stage最后一个rdd下游rdd的shuffle依赖
val parents: List[Stage] // 当前stage的父stage
) {}
stage提交
主要涉及的方法
- submitStage
- getMissingParentStages:dfs遍历rdd的方式找到当前stage未完成的父stage
- submitMissingTasks
submitStage中调用getMissingParentStages获取当前stage未完成的父stage。若其父stage都已完成,则调用submitMissingTasks提交当前stage;否则对所有未完成的父stage递归调用submitStage。递归的方式从最初stage开始提交。
submitMissingTasks实际执行stage的提交,若当前stage为整个dag最后一个stage,则提交ResultTask类型任务;否则提交ShuffleMapTask类型任务。任务提交调用submitTasks方法(由具体DAGScheduler实现重写)。
结束
任务提交之后,driver在循环中监听事件,对任务执行状况进行调度、监控。具体细节待研究。当接收到成功事件时,若成功的为ResultTask,则job执行完毕;当成功的为ShuffleMapTask,会将成功的stage的输出通过registerMapOutputs方法注册到MapOutputTracker。