Spark运行流程

本文深入探讨了Spark中DAG图的构建过程,详细解释了如何从代码中生成DAG,以及Spark如何通过宽依赖将DAG划分为多个Stage进行高效计算。此外,还介绍了Stage提交、任务调度、结果监控及获取的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1.1.计算流程

IMG_272

 

IMG_278

592648-20160720092452294-719908979

IMG_273

 

1.1.2. 从代码构建DAG

Spark program
Val lines1 = sc.textFile(inputPath1).map(...).map(...)
Val lines2 = sc.textFile(inputPath2).map(...)
Val lines3 = sc.textFile(inputPath3)
Val dtinone1 = lines2.union(lines3)
Val dtinone = lines1.join(dtinone1)
dtinone.saveAsTextFile(...)
dtinone.filter(...).foreach(...)

Spark的计算发生在RDDAction操作,而对Action之前的所有TransformationSpark只是记录下RDD生成的轨迹,而不会触发真正的计算。
Spark内核会在需要计算发生的时刻绘制一张关于计算路径的有向无环图,也就是DAG

 

IMG_279

 

1.1.3. DAG划分为Stage核心算法

Application多个job多个Stage

Spark Application中可以因为不同的Action触发众多的job,一个Application中可以有很多的job,每个job是由一个或者多个Stage构成的,后面的Stage依赖于前面的Stage,也就是说只有前面依赖的Stage计算完毕后,后面的Stage才会运行。

划分依据:

Stage划分的依据就是宽依赖,何时产生宽依赖,reduceByKey, groupByKey等算子,会导致宽依赖的产生。

核心算法:

  1. 从后往前回溯/反向解析,遇到窄依赖加入本stage,遇见宽依赖进行Stage切分。
  2. Spark内核会从触发Action操作的那个RDD开始从后往前推,
  3. 首先会为最后一个RDD创建一个stage
  4. 然后继续倒推,如果发现对某个RDD是宽依赖,那么就会将宽依赖的那个RDD创建一个新的stage,那个RDD就是新的stage的最后一个RDD
  5. 然后依次类推,继续倒推,根据窄依赖或者宽依赖进行stage的划分,直到所有的RDD全部遍历完成为止。

1.1.4. DAG划分为Stage剖析

HDFS中读入数据生成3个不同的RDD,通过一系列transformation操作后再将计算结果保存回HDFS
可以看到这个DAG中只有join操作是一个宽依赖,Spark内核会以此为边界将其前后划分成不同的Stage.
同时我们可以注意到,在图中Stage2中,从mapunion都是窄依赖,这两步操作可以形成一个流水线操作,通过map操作生成的partition可以不用等待整个RDD计算结束,而是继续进行union操作,这样大大提高了计算的效率。

 

IMG_280

 

 

1.1.5. 提交Stages

调度阶段的提交,最终会被转换成一个任务集的提交,
DAGScheduler通过TaskScheduler接口提交任务集,
这个任务集最终会触发TaskScheduler构建一个TaskSetManager的实例来管理这个任务集的生命周期,
对于DAGScheduler来说,提交调度阶段的工作到此就完成了。
TaskScheduler的具体实现则会在得到计算资源的时候,进一步通过TaskSetManager调度具体的任务到对应的Executor节点上进行运算。

 

IMG_287

 

 

1.1.6. 监控JobTaskExecutor

l  DAGScheduler监控JobTask

要保证相互依赖的作业调度阶段能够得到顺利的调度执行,DAGScheduler需要监控当前作业调度阶段乃至任务的完成情况。
这通过对外暴露一系列的回调函数来实现的,对于TaskScheduler来说,这些回调函数主要包括任务的开始结束失败、任务集的失败,DAGScheduler根据这些任务的生命周期信息进一步维护作业和调度阶段的状态信息。

l  DAGScheduler监控Executor的生命状态:

TaskScheduler通过回调函数通知DAGScheduler具体的Executor的生命状态,如果某一个Executor崩溃了,则对应的调度阶段任务集的ShuffleMapTask的输出结果也将标志为不可用,这将导致对应任务集状态的变更,进而重新执行相关计算任务,以获取丢失的相关数据。

1.1.7. 获取任务执行结果

l结果DAGScheduler

一个具体的任务在Executor中执行完毕后,其结果需要以某种形式返回给DAGScheduler,根据任务类型的不同,任务结果的返回方式也不同。

l两种结果,中间结果与最终结果:

对于FinalStage所对应的任务,返回给DAGScheduler的是运算结果本身,而对于中间调度阶段对应的任务ShuffleMapTask,返回给DAGScheduler的是一个MapStatus里的相关存储信息,而非结果本身,这些存储位置信息将作为下一个调度阶段的任务获取输入数据的依据。

l两种类型,DirectTaskResultIndirectTaskResult

根据任务结果大小的不同,ResultTask返回的结果又分为两类:

 

  1. 如果结果足够小,则直接放在DirectTaskResult对象内中,
  2. 如果超过特定尺寸则在Executor端会将DirectTaskResult先序列化,再把序列化的结果作为一个数据块存放在BlockManager中,然后将BlockManager返回的BlockID放在IndirectTaskResult对象中返回给TaskSchedulerTaskScheduler进而调用TaskResultGetterIndirectTaskResult中的BlockID取出并通过BlockManager最终取得对应的DirectTaskResult

 

 

1.1.8. 任务调度总体诠释

 

IMG_292

 

 



转载于:https://www.cnblogs.com/TiePiHeTao/p/bd6b2eac4d02c5279e702eb3b71a3d89.html

### Apache Spark 执行流程详解 #### 1. SQL 解析阶段 当用户通过 Spark 提交一条 SQL 查询时,SQL 首先进入解析器 (Parser),该解析器会将字符串形式的 SQL 转换为逻辑计划 (Logical Plan)[^1]。此阶段的主要目标是验证语法正确性和语义一致性。 #### 2. Analyzer 阶段 经过解析后的逻辑计划会被传递到 Analyzer 组件,在这里会对表名、列名以及数据类型进行绑定操作,并解决未解析的对象引用问题。Analyzer 还负责处理视图展开和其他元数据查询工作[^1]。 #### 3. Optimizer 阶段 优化器 (Catalyst Optimizer) 接收来自 Analyzer 的分析完成的逻辑计划并对其进行一系列代数变换来生成更高效的物理执行方案。这些转换可能包括但不限于谓词下推、常量折叠、投影裁剪等技术手段以减少不必要的计算开销。 #### 4. Physical Planning Stage 在这个阶段中, Catalyst 将抽象出来的最佳逻辑执行路径转化为具体的 RDD 或 Dataset/DatFrame API 调用序列即所谓的 “SparkPlan”。这一步骤定义了如何实际地分布于集群之上运行作业的任务分配策略[^1]。 #### 5. Stages 划分与调度 为了提高效率和容错能力,SparK 把整个应用程序拆分成若干个小部分或者说是 stages 来分别处理不同的输入分区集合。如果存在 shuffle 操作,则意味着需要创建一个新的 stage ,因为只有当前面所有的 map 输出都已准备好之后才可以开始 reduce 计算[^3]。 #### 6. Task Execution 最后由 scheduler 向 worker 发送 task 求去执行相应的 transformation 和 action 。每个 executor 上都会启动一定数量的核心用于并发执行 tasks [^2]。 ```python from pyspark.sql import SparkSession # 创建 Spark Session 实例 spark = SparkSession.builder.appName("example").getOrCreate() # 加载数据集 df = spark.read.format("csv").option("header", "true").load("/path/to/data") # 注册临时视图表以便后续查询使用 df.createOrReplaceTempView("table_name") # 编写 SQL 并触发执行 result_df = spark.sql(""" SELECT column_a, SUM(column_b) AS sum_b FROM table_name GROUP BY column_a """) # 展示结果 result_df.show() ``` 以上代码片段展示了从加载 CSV 文件作为 DataFrame 开始到最后展示聚合结果的过程。它涵盖了 Spark SQL 中涉及的关键步骤:读取外部存储中的数据源;注册成可供 SQL 查找使用的虚拟关系型数据库对象;编写标准结构化查询语言表达式来进行数据分析任务;最终呈现汇总统计信息给终端使用者查看。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值