TaskScheduler可以看做任务调度的客户端,负责任务的提交,并且请求集群管理器对任务调度。TaskScheduler的类UML图如下,针对不同部署方式会有不同的TaskScheduler与SchedulerBackend进行组合。TaskScheduler类负责任务调度资源的分配,SchedulerBackend负责与Driver、Executor通信收集Executor上分配给该应用的资源使用情况。常见的任务调度模式有以下四种:
- Local模式:TaskSchedulerImpl + LocalBackend
- Standalone模式:TaskSchedulerImpl + StandaloneSchedulerBackend
- Yarn-Cluster模式:YarnClusterScheduler + YarnClusterSchedulerBackend
- Yarn-Client模式:YarnScheduler + YarnClientSchedulerBackend
下面以最常用的Yarn-Cluster模式为例,从以下四个步骤来分析源码实现方式:
- TaskScheduler的创建;
- Task的提交;
TaskScheduler的创建
-
TaskScheduler是在SparkContext中定义并启动的:
// We need to register "HeartbeatReceiver" before "createTaskScheduler" because Executor will // retrieve "HeartbeatReceiver" in the constructor. (SPARK-6640) // 需要在createTaskScheduler调用前注册HeartbeatReceiver,因为Executor在构造时就要检索HeartbeatReceiver消息 _heartbeatReceiver = env.rpcEnv.setupEndpoint( HeartbeatReceiver.ENDPOINT_NAME, new HeartbeatReceiver(this)) // master是"spark.master"参数的值,deployMode是"spark.submit.deployMode"参数的值 // Create and start the scheduler // 创建task scheduler,返回(backend, scheduler)的Tuple val (sched, ts) = SparkContext.createTaskScheduler(this, master, deployMode) _schedulerBackend = sched _taskScheduler = ts // DAGScheduler中保存有taskScheduler的引用,同样构造DAGScheduler时也将自身引用设置到taskScheduler中 _dagScheduler = new DAGScheduler(this) // 向HeartbeatReceiver发送一条SparkContext.taskScheduler已经创建好的消息 _heartbeatReceiver.ask[Boolean](TaskSchedulerIsSet) // start TaskScheduler after taskScheduler sets DAGScheduler reference in DAGScheduler's // constructor // 在DAGScheduler的构造器中将自身的引用设置到taskScheduler里之后,启动TaskScheduler, // 方法中同时也会调用backend.start方法启动backend _taskScheduler.start()
-
TaskScheduler的构建
createTaskScheduler方法会根据master参数匹配部署模式,创建TaskSchedulerImpl,并生成不同的SchedulerBackend(Yarn-Cluster模式:YarnClusterScheduler + YarnClusterSchedulerBackend)。
master match { case masterUrl => val cm = getClusterManager(masterUrl) match { case Some(clusterMgr) => clusterMgr case None => throw new SparkException("Could not parse Master URL: '" + master + "'") } try { // 利用集群管理器创建TaskScheduler val scheduler = cm.createTaskScheduler(sc, masterUrl) // 利用集群管理器创建SchedulerBackend,并且将scheduler的引用传入 val backend = cm.createSchedulerBackend(sc, masterUrl, scheduler) // 内部调用TaskSchedulerImpl.initialize方法将backend引用设置到scheduler中, // 并根据schedulingMode创建调度管理器FIFOScheduler或者FairSched