Spark DAGScheduler 功能及源码解析

Spark 源码解析 : DAGScheduler中的DAG划分与提交 一、Spark 运行架构 Spark 运行架构如下图: 各个RDD之间存在着依赖关系,这些依赖关系形成有向无环图DAG,DAGScheduler对这些依赖关系形成的DAG,进行Stage划分,划分的规则很简单,从后往前回溯,遇到窄依赖加入本stage,遇见宽依赖进行Stage切分。完成了Stage的划分,DAGScheduler基于每个Stage生成TaskSet,并将Ta 阅读详情

Spark中DAGScheduler的主要作用是将Job按照RDD的依赖关系划分成若干个TaskSet,也称为Stage;之后结合当前缓存情况及数据就近的原则,将Stage提交给TaskScheduler

private[spark]
class DAGScheduler(
    private[scheduler] val sc: SparkContext,
    private[scheduler] val taskScheduler: TaskScheduler,
    listenerBus: LiveListenerBus,
    mapOutputTracker: MapOutputTrackerMaster,
    blockManagerMaster: BlockManagerMaster,
    env: SparkEnv,
    clock: Clock = new SystemClock())
  extends Logging

从类的定义中看到,涉及到作为Spark入口的SparkContext;用于执行task的TaskScheduler;处理RDD计算过程中的Map信息的MapOutputTrackerMaster;以及管理block存储的BlockManagerMaster

RDD的action操作,比如count,reduce等,会触发SparkContext.runJob方法,后者实际最终调用的是DAGScheduler.submitJob方法

// DAGScheduler.submitJob
def submitJob[T, U](
    rdd: RDD[T],
    func: (TaskContext, Iterator[T]) => U,
    partitions: Seq[Int],
    callSite: CallSite,
    allowLocal: Boolean,
    resultHandler: (Int, U) => Unit,
    properties: Properties): JobWaiter[U] = {
  // Check to make sure we are not launching a task on a partition that does not exist.
  val maxPartitions = rdd.partitions.length
  partitions.find(p => p >= maxPartitions || p < 0).foreach { p =>
    throw new IllegalArgumentException(
      "Attempting to access a non-existent partition: " + p + ". " +
        "Total number of partitions: " + maxPartitions)
  }

  val jobId = nextJobId.getAndIncrement()
  if (partitions.size == 0) {
    return new JobWaiter[U](this, jobId, 0, resultHandler)
  }

  assert(partitions.size > 0)
  val func2 = func.asInstanceOf[(TaskContext, Iterator[_]) => _]
  val waiter = new JobWaiter(this, jobId, partitions.size, resultHandler)
  // post方法将event加入队列,执行是由另外的线程遍历队列来处理
  eventProcessLoop.post(JobSubmitted(
    jobId, rdd, func2, partitions.toArray, allowLocal, callSite, waiter,
    SerializationUtils.clone(properties)))
  waiter
}

JobSubmitted是继承了DAGSchedulerEvent特征的子类,DAGScheduler可以处理的事件类型都被包装成了DAGSchedulerEvent

eventProcessLoop是DAGSchedulerEventProcessLoop类的实例,后者是DAGScheduler的私有类,继承了EventLoop类,主要通过调用onReceive方法来单线程的处理队列中的event

Notice:EventLoop.post方法只是将event装入队列,真正的处理是由单线程的eventThread来遍历队列,对取出的事件调用EventLoop.onReceive(event)方法。因此不同的线程可以同时提交事件,不会存在冲突,但不保证事件会立即被执行

DAGSchedulerEventProcessLoop覆盖了父类的onReceive方法,我们可以看到JobSubmitted对应的是DAGScheduler.handleJobSubmitted方法

// DAGSchedulerEventProcessLoop.onReceive
override def onReceive(event: DAGSchedulerEvent): Unit = event match {
  case JobSubmitted(jobId, rdd, func, partitions, allowLocal, callSite, listener, properties) =>
    dagScheduler.handleJobSubmitted(jobId, rdd, func, partitions, allowLocal, callSite,
      listener, properties)

  case StageCancelled(stageId) =>
    dagScheduler.handleStageCancellation(stageId)

  ...
}
// DAGScheduler.handleJobSubmitted
private[scheduler] def handleJobSubmitted(jobId: Int,
    finalRDD: RDD[_],
    func: (TaskContext, Iterator[_]) => _,
    partitions: Array[Int],
    allowLocal: Boolean,
    callSite: CallSite,
    listener: JobListener,
    properties: Properties) {
  var finalStage: ResultStage = null
  try {
    // New stage creation may throw an exception if, for example, jobs are run on a
    // HadoopRDD whose underlying HDFS files have been deleted.
    finalStage = newResultStage(finalRDD, partitions.size, jobId, callSite)
  } catch {
    case e: Exception =>
      logWarning("Creating new stage failed due to exception - job: " + jobId, e)
      listener.jobFailed(e)
      return
  }
  if (finalStage != null) {
    val job = new ActiveJob(jobId, finalStage, func, partitions, callSite, listener, properties)
    clearCacheLocs()
    logInfo("Got job %s (%s) with %d output partitions (allowLocal=%s)".format(
      job.jobId, callSite.shortForm, partitions.length, allowLocal))
    logInfo("Final stage: " + finalStage + "(" + finalStage.name + ")")
    logInfo(
【Spark】DAGScheduler源码浅析 DAGSchedulerDAGScheduler的主要任务是基于Stage构建DAG,决定每个任务的最佳位置 记录哪个RDD或者Stage输出被物化 面向stage的调度层,为job生成以stage组成的DAG,提交TaskSet给TaskScheduler执行 重新提交shuffle输出丢失的stage 每一个Stage内,都是独立的tasks,他们共同执行同一个compu 阅读详情

相关推荐

[Spark源码剖析] DAGScheduler划分stage

本文基于Spark 1.3.1 先上一些stage相关的知识点: DAGScheduler将Job分解成具有前后依赖关系的多个stage DAGScheduler是根据ShuffleDependency划分stage的 stage分为ShuffleMapStage和ResultStage;一个Job中包含一个ResultStage及多个ShuffleMapStage 一个stage包含多个tasks

Bbbbbbbbbbbbig data~ 2032

Spark军师之DAGScheduler

       搬个凳子,捧着瓜子,让我们开始唠嗑。      首先,字面解读下“DAGScheduler”,可以理解为是一个DAG调度器,DAG又是啥呢?学术名叫:有向无环图。一个spark应用程序提交,spark引擎就是通过DAGScheduler将其切分成一个个stage。让我们先来看看DAGScheduler是在哪里起的作用的。经典图:    那这个DAGScheduler的职能到底是什么呢...

crazy246的专栏 2080

光谱预处理最简单实现方法--基于OpenSA光谱分析库

系列文章目录 “光晰本质,谱见不同”,光谱作为物质的指纹,被广泛应用于成分分析中。伴随微型光谱仪/光谱成像仪的发展与普及,基于光谱的分析技术将不只停留于工业和实验室,即将走入生活,实现万物感知,见微知著。本系列文章致力于光谱分析技术的科普和应用。 文章目录系列文章目录前言一、数据来源二、代码解读2.1 读取数据2 .2 划分数据集2 .3 返回训练集和测试集并绘制光谱图片2.4 建立1-D CNN模型2.5 训练1-D CNN模型2.6 测试1-D CNN模型2.7 运行CNN模型,并用查看结果总结

Echo_Code的博客 7067

ServiceNow Discovery & CMDB Interview Questions and Answers (2025)

【代码】ServiceNow Discovery & CMDB Interview Questions and Answers (2025)

weixin_47584092的博客 910

开发板的使用

一、开发板使用学习大纲。 1、开发板组成、核心板资源,底板资源。 2、开发板连接、调试工具、串口参数配置。 3、开发板启动过程。 4、文件传输 1)使用串口传输。 上传/下载 2)使用网口传输。 上传/下载 5、临时/永久配置开发板IP地址。 6、开发板启动脚本。 二、开发板的组成。 核心板: CPU处理器: 芯片:S5P6818(三星) 内核: ARM cortex-A53 -> 八核处理器 运行内存:512MB*2=1G nandflash:4G 底板: 电源线:5V 串口...

qq_45633736的博客 2659

NVIDIA DGX Spark (Ubuntu 24.04) 部署Isaac Sim与Isaac Lab:二进制安装与ROS2集成实战

本文详细介绍了在NVIDIA DGX Spark工作站(Ubuntu 24.04系统)上,通过预编译二进制包稳定部署Isaac Sim与Isaac Lab的完整实战流程。文章重点剖析了二进制安装相较于源码编译和pip安装的优势,有效规避了CUDA、PyTorch等关键组件的版本冲突陷阱,并逐步指导完成环境配置、Isaac Lab集成、Conda环境管理以及ROS2 Jazzy的集成,最终构建出完整的机器人仿真与强化学习开发平台。

kite3的博客 396

QGis二次开发 —— 2、第一个程序 - 加载栅格tif与矢量shp文件(附源码)

QGis二次开发 —— 2、第一个程序 - 加载栅格tif与矢量shp文件(附源码)

1100

OpenClaw人人养虾:接入即时通讯平台Zalo

通过 Zalo Official Account(OA,官方账号)API,可以将 OpenClaw 接入 Zalo,实现面向越南用户的自动化客服和互动。

王国平的博客 437

GoAnywhere MFT 身份验证绕过漏洞(CVE-2024-0204)

GoAnywhere MFT 身份验证绕过漏洞(CVE-2024-0204)

weixin_43567873的博客 387

Flutter框架GetX从入门到精通第二篇:路由管理-告别繁琐的Navigator

Flutter框架GetX从入门到精通第二篇:告别繁琐的Navigator。本系列将带你从零开始,一步步掌握 GetX 框架的核心功能与实战技巧。

鹏多多的博客 171

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: Spark Partitioner源码
下一篇: Spark TaskScheduler 功能及源码解析
威廉的大数据实验室
博客等级 码龄12年 32粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值