RDD任务切分之Stage任务划分(图解和源码)

本文深入探讨了Apache Spark中RDD的任务调度机制,包括Application、Job、Stage和Task的概念及其关系。详细分析了从Action算子触发到Task执行的全过程,以及DAGScheduler如何将Job划分为Stage,并最终确定Task的执行计划。

RDD任务切分中间分为:Application、Job、Stage和Task

(1)Application:初始化一个SparkContext即生成一个Application;

(2)Job:一个Action算子就会生成一个Job;

(3)Stage:Stage等于宽依赖的个数加1;

(4)Task:一个Stage阶段中,最后一个RDD的分区个数就是Task的个数。

注意:Application->Job->Stage->Task每一层都是1对n的关系

主要步骤

// 代码样例
def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)
    val rdd:RDD[String] = sc.textFile("input/1.txt")
    val mapRdd = rdd.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
    mapRdd.saveAsTextFile("outpath")
    //3.关闭连接
    sc.stop()
  }

先看下执行流程图(Yarn-Cluster)

现在一步一步分析

第一步

  • 执行main方法

  • 初始化sc

  • 执行到Action算子

这个阶段会产生血缘依赖关系,具体的代码并没有执行

第二步:DAGScheduler对上面的job切分stage,stage产生task

DAGScheduler: 先划分阶段(stage)再划分任务(task)

这个时候会产生Job的stage个数 = 宽依赖的个数+1 = 2 (这个地方产生一个宽依赖),也就是产生shuffle这个地方

Job的Task个数= 一个stage阶段中,最后一个RDD的分区个数就是Task的个数(2+2 =4)shuffle前的ShuffleStage产生两个

shuffle后reduceStage产生两个

第三步:TaskSchedule通过TaskSet获取job的所有Task,然后序列化分给Exector

job的个数也就是 = Action算子的个数(这里只一个collect)

 源码分析

一步一步从collect()方法找下会找到这段主要代码

———————————————————————————————1—————————————————————————————————
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 = createResultStage(finalRDD, func, partitions, jobId, callSite)
    } catch {
      case e: Exception =>
        logWarning("Creating new stage failed due to exception - job: " + jobId, e)
        listener.jobFailed(e)
        return
    }


finalStage = createRe
### Apache Spark Stage 划分源码分析 #### 程序入口与初始化 当执行 `spark-submit` 命令时,实际调用的是位于 `${SPARK_HOME}/bin/` 下的 `spark-class` 脚本。此脚本最终会启动 `org.apache.spark.deploy.SparkSubmit` 类来处理命令行参数并准备应用程序环境[^1]。 ```bash exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@" ``` #### DAGScheduler Stage 划分逻辑 DAGScheduler 是负责管理作业调度的核心组件之一,在接收到由驱动器端发起的动作操作(action)请求之后,DAGScheduler 将构建有向无环图(Directed Acyclic Graph, DAG),并将该图形转换成一系列的任务(TaskSet)[^2]。具体来说: - **Job 提交**: 当用户提交一个 Action 操作给 Spark 应用程序时,这将触发一个新的 Job 创建。 - **Stage 构建**: 对于每一个新创建的 Job,DAGScheduler 需要解析构成这个 Job 的所有宽依赖关系(Wide Dependency)窄依赖关系(Narrow Dependency), 并据此定义多个 Stage。每个 Stage 内部只包含具有窄依赖的数据流变换;而不同 Stages 之间则存在宽依赖边界[^3]。 - **Parent RDDs 获取**: 在确定如何分割这些 Stage 后,DAGScheduler 使用 `RDD.getDependencies()` 方法获取当前 RDD 所有的父级 RDD 实例列表作为依据来进行进一步划分[^4]。 #### 结果计算阶段( Result Stage ) 对于那些直接对应于某些特定动作的操作而言,比如 `count()`, `saveAsTextFile()` 或者其他任何返回值类型的 API ,它们会被视为特殊的 Stage 称之为 “Result Stage”。这类 Stage 特指那部分能够立即产出最终结果数据集合的工作单元。 ```scala // 示例代码片段展示了一个简单的Action操作是如何被转化为ResultStage的. val rdd = sc.parallelize(Seq(("a", 1), ("b", 2))) rdd.count() ``` 上述例子中,`count()` 动作将会促使系统生成相应的 ResultStage 来完成计数统计工作。 #### 完整流程总结 综上所述,整个 Stage 划分过程大致如下: - 用户通过 `spark-submit` 发起应用; - SparkSubmit 解析配置项并向集群申请资源; - Driver 接收到来自 Client 的指令后开始构建 DAG 图形结构; - 根据不同的 ShuffleDependency 关系割出独立运作的小型任务组即 Stage; - 如果遇到 Action 类型的操作,则额外形成专门用于求解终态数据的结果 Stage
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值