Stage划分源码分析

Spark源码学习: stage的划分方式 之前学习Spark的时候, 关于宽窄依赖以及stage划分, 一直都知道几句话: 宽依赖和窄依赖的一个重要区别是有无shuffle 根据宽依赖来进行stage划分 在DAG中进行反向解析, 遇到宽依赖就断开, 遇到窄依赖就把当前的RDD加入到当前的阶段中 虽然知道了, 但是好像跟背书没什么区别. 还是得知其所以然的 直接看涉及stage划分的这段源码吧. 定位起来也很简单, 写一个Action... 阅读详情

概述

stage 划分思想:
  由submitStage() 和getMissingParentStage() 组成。会从触发Action操作的那个RDD开始往前,首先为最后一个RDD创建一个stage,然后再往前,如果遇到某个RDD是宽依赖,就会为宽依赖创建一个新的stage,新的RDD就是最新的stage的最后一个RDD。然后依次类推,继续往前,根据宽依赖或者窄依赖进行stage划分,直到最后一个RDD遍历完为止

窄依赖:父RDD和子RDDpartition之间是一对一或多对一
宽依赖:父RDD和子RDD partition之间是一对多
  窄依赖一般是对RDD进行map,filter,union等Transformations。宽依赖一般是对RDD进行groupByKey,reduceByKey等操作,就是对RDD中的partition中的数据进行重分区(shffle)。join操作既可能是宽依赖也可能是窄依赖,当要对RDD进行join操作时,如果RDD进行过重分区则为宽依赖,否则为窄依赖。

为什么要根据宽依赖划分stage
  窄依赖会被划分到同一个Stage中,这样就能以管道的方式迭代执行。宽依赖由于依赖的上游RDD,需要首先计算好所有父分区数据,然后在节点间进行shuffle。从容灾角度讲,它们恢复计算结果的方式不同。窄依赖只需要重新执行父RDD的丢失分区的计算即可恢复。而宽依赖则需要考虑恢复所有父RDD的丢失分区并且同一RDD下的其他分区数据也重新计算了一次。

提交stage的方法(stage划分算法入口):
  调用 getMissingParentStage() 获取当前这个 stage 的父 stage;往栈中推入stage的最后一个RDD;while循环对stage的最后一个RDD,调用visit()方法:如果是窄依赖,将RDD放入栈中,如果是宽依赖,使用宽依赖的那个RDD创建一个stage,将isShuffleMap设为true;提交stage,为stage创建一批task,task数量与Partition数量相同;计算每个task对应的Partition的最佳位置(从stage最后一个RDD开始,去找被cache或checkpoint的RDD的Partition,task的最佳位置,就是该Partition的位置,这样task就在那个节点上执行,不需要计算之前的RDD;如果从最后一个RDD到最开始的RDD,都没有被cache或checkpoint,那么最佳位置就是Nil,即没有最佳位置)。针对stage的task,创建TaskSet对象,调用TaskScheduler的submitTask方法,提交TaskSet,提交到Excutor上去执行

即:

1、从finalstage倒推,
2、通过宽依赖进行新的stage划分
3、使用递归,优先提交父stage

源码剖析

Stage的划分

  进入submitJob方法,首先会去检查rdd的分区信息,在确保rdd分区信息正确的情况下,给当前job生成一个jobId,从0开始编号,在同一个SparkContext中,jobId会逐渐顺延。然后构造出一个JobWaiter对象返回给上一级调用函数。通过eventProcessLoop提交该任务,最终会调用到DAGScheduler.handleJobSubmitted来处理这次提交的Job。

DAGScheduler.eventProcessLoop.post( JobSubmitted(...) )
DAGScheduler.handleJobSubmitted

  在DAGScheduler内部通过post一个JobSubmitted事件来触发Job的提交。EventProcessLoop类继承自EventLoop类,其中的post方法也是在EventLoop中定义的。在EventLoop中维持了一个LinkedBlockingDeque类型的事件队列,将该Job提交事件存入该队列后,事件线程会从队列中取出事件并进行处理。
  提交的JobSubmitted事件,实际上调用了DAGScheduler的handleJobSubmitted方法。DAGScheduler.handleJobSubmitted通过调用newResultStage函数来创建finalStage。调用newResultStage时,传入了finalRDD、partitions.size等参数。

finalStage = newResultStage(finalRDD, partitions.size, jobId, callSite)

  在DAGScheduler.newResultStage首先调用getParentStagesAndId(rdd, jobId)。这个方法主要是为当前的RDD向前探索,找到宽依赖处划分出parentStage,并为当前RDD所属Stage生成一个stageId。在这个方法中,getParentStages的调用链最终递归调用到了这个方法,所以,最后一个Stage的stageId最大,越往前的stageId就越小,stageId小的Stage先执行。
  跟到getParentStages里。在函数getParentStages中,遍历整个RDD依赖图的finalRDD的List[dependency] ,若遇到ShuffleDependency(即宽依赖),则调用getShuffleMapStage(shufDep, jobId)返回一个ShuffleMapStage类型对象,添加到父stage列表中。而窄依赖的RDD,继续压入栈中,直到遇到ShuffleDependency或无依赖的RDD。
  跟进到函数getShuffleMapStage的实现。getShuffleMapStage为当前宽依赖的Map端生成一个新的ShuffleMapStage类型的Stage。同时也为当前Shuffle的父Shuffle生成一个Stage。通过DAGScheduler.getAncestorShuffleDependencies获取当前Shuffle的父Shuffle,这个方法的实现与getParentStages基本一致,不同的是这里是将宽依赖加入到parents中并返回。
  registerShuffleDependencies拿到各个“依赖路线”最近的所有宽依赖后。对每个宽依赖调用newOrUsedShuffleStage,该函数用来创建新ShuffleMapStage或获得已经存在的ShuffleMapStage。
  函数newOrUsedShuffleStage首先调用newShuffleMapStage来创建新的ShuffleMapStage。newShuffleMapStage调用getParentStagesAndId来获取它的parentStages。那么,整个函数调用流程又会继续走一遍,不同的是起点rdd不是原来的finalRDD而是变成了这里的宽依赖的rdd。

Stage的提交

任务的提交和生成入口在DAGScheduler.handleJobSubmitted方法中。

DAGScheduler.handleJobSubmitted
  生成了finalStage后,就会为该Job生成一个ActiveJob对象了,并准备计算这个finalStage。在DAGScheduler.handleJobSubmitted方法的最后,调用了DAGScheduler.submitStage方法,在提交finalStage的前面,会通过listenerBus的post方法,把Job开始的事件提交到Listener中。

DAGScheduler#submitStage
  Job的提交,是从最后那个Stage开始的。如果当前stage已经被提交过,处于waiting状态或者当前stage已经处于failed状态则不作任何处理,否则继续提交该stage。
  在提交时,需要当前Stage需要满足依赖关系,其前置的Parent Stage都运行完成后才能轮得到当前Stage运行。如果还有Parent Stage未运行完成,则优先提交Parent Stage。通过调用方法DAGScheduler.getMissingParentStages方法获取未执行的Parent Stage。如果当前Stage满足上述两个条件后,调用DAGScheduler.submitMissingTasks方法,提交当前Stage。

DAGScheduler.getMissingParentStage
  这个方法用于获取stage未执行的Parent Stage。在上面方法中,获取到Parent Stage后,递归调用上面那个方法按照StageId小的先提交的原则,这个方法的逻辑和DAGScheduler.getParentStages方法类似。总之就是根据当前Stage,递归调用其中的visit方法,依次对每一个Stage追溯其未运行的Parent Stage。

DAGScheduler.submitMissingTasks
  当Stage的Parent Stage都运行完毕,才能调用这个方法真正的提交当前Stage中包含的Task。

DAG生成

  DAG是有向无环图,原始的RDD通过一系列的转换就形成了DAG,根据RDD之间依赖关系的不同将DAG划分成不同的Stage(调度阶段)。对于窄依赖,partition的转换处理在一个Stage中完成计算。对于宽依赖,由于有Shuffle的存在,只能在parent RDD处理完成后,才能开始接下来的计算,因此宽依赖是划分Stage的依据。一个Spark的Application应用中一个或者多个DAG(也就是一个Job),取决于触发了多少次Action。一个DAG中会有不同的阶段/stage,划分阶段/stage的依据就是宽依赖。一个阶段/stage中可以有多个Task,一个分区对应一个Task。

DAG的边界:
开始:通过SparkContext创建的RDD
触发Action,一旦触发Action就形成了一个完整的DAG

Spark源码分析之三:Stage划分 继上篇《Spark源码分析之Job的调度模型与运行反馈》之后,我们继续来看第二阶段--Stage划分。         Stage划分的大体流程如下图所示:         前面提到,对于JobSubmitted事件,我们通过调用DAGScheduler的handleJobSubmitted()方法来处理。那么我们先来看下代码: // 处理Job提交的函数 private[sch 阅读详情

相关推荐

Spark的stage划分算法源码分析

Spark Application中可以有不同的Action触发多个Job,也就是说一个Application中可以有很多的Job,每个Job是由一个或者多个Stage构成的,后面的Stage依赖于前面的Stage,也就是说只有前面依赖的Stage计算完毕后,后面的Stage才会运行。 然而Stage划分的依据就是宽依赖,什么时候产生宽依赖(产生shuffle)呢?例如reduceByKey,...

chenfengdejuanlian的专栏 904

Stage的划分

宽窄依赖 RDD之间有一系列的依赖关系,依赖关系又分为窄依赖和宽依赖。Spark中的Stage其实就是一组并行的任务,任务是一个个的task 。 宽依赖(Shuffle Dependency) 父RDD与子RDD partition之间的关系是一对多。会有shuffle的产生。父RDD的一个分区的数据去到子RDD的不同分区里面。 窄依赖 (Narrow Dependency) 父RDD和子RDD partition之间的关系是一对一的。或者父RDD一个partition只对应一个子RDD的part

weixin_41618692的博客 2174

Java Swing 实现超级马里奥小游戏:主循环、碰撞检测与帧率解耦

游戏开发中,主循环、碰撞检测与帧率控制是核心基础。Java Swing 作为 JDK 自带的 GUI 工具包,通过 JPanel 与 Timer 即可构建 2D 游戏循环,利用 AABB 矩形碰撞检测实现物体交互,并借助 deltaTime 解耦帧率与移动速度,保证不同设备上的手感一致。这些技术不仅适用于小游戏,也是理解游戏引擎原理的入口。本文以 Java 超级马里奥小游戏为例,详细讲解从窗口搭建、瓦片地图、重力跳跃到避坑排查的完整实践,帮助 Java 初学者和面试准备者掌握面向对象与状态机的落地。

weixin_34234829的博客 392

34 Spark中任务处理的Stage划分和Task最佳位置算法

本节课的内容 1. Job Stage的划分算法 2. Task最佳计算位置算法

Hipparchus的博客 1万+

Stage划分算法原理剖析.pdf

对Spark 中Stage划分的分析,很详细。如果有不清楚的地方可以一起谈论

Stage划分算法原理剖析

Stage划分算法原理剖析

spark调度体系——stage划分

rdd中的action算子,会触发job任务计算。以collect算子举例,可以看到最后是调用的DAGScheduler的submitJob方法DAGScheduler的runJob调用的是submitJob方法。submitJob是先生成新的jobId,发送JobSubmitted的消息。DAGScheduler收到JobSubmitted消息后,调用handleJobSubmitted方法。handleJobSubmitted调用createResultStage方法。

weixin_43839095的博客 807

SpringBoot使用mybatis-plus的自动代码生成器

一.SpringBoot使用mybatis-plus+自动代码生成 使用mybatis-plus可以自动帮我们生成通用的 controller,service,dao,mapper 二.加入依赖 <!-- MP 核心库 --> <dependency> <groupId>com.baomidou</groupId> <artif...

农民娃儿的博客 2263

17、stage划分算法原理及DAGScheduler源码分析

一、stage划分算法原理1、图解二、DAGScheduler源码分析1、###org.apache.spark/SparkContext.scala // 调用SparkContext,之前初始化时创建的dagScheduler的runJob()方法 dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, allowLoc...

weixin_30817749的博客 127

XGBoost实战:从原理到调参,手把手教你提升模型性能(附Python代码)

本文深入解析XGBoost核心原理,并提供一套从数据准备、系统性调参到生产部署的完整实战指南。通过剖析目标函数、正则化项与分裂算法,帮助读者理解参数背后的数学逻辑,并利用交叉验证、早停法及自动化工具(如Optuna)高效提升模型性能。文中附有详尽的Python代码示例,涵盖类别特征处理、缺失值应对、不平衡数据调整及模型可视化等高级技巧。

weixin_29178069的博客 457

【ROS学习笔记】8.话题消息(Message)的定义与使用

ROS学习笔记8——话题消息(Message)的定义与使用

takedachia的博客 9548

spark1.2.0源码分析之ShuffledRDD的Stage划分

当调用reduceByKey()、groupByKey()等操作后,会伴随着ShuffledRDD的生成,具体源码如下: def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)] = { combineByKey[V]((v: V) => v, func, func, partitioner)

Yobadman的专栏 2161

秦时明月6.2魔改版_从零到一部署指南_含安卓客户端配置与GM后台直通

本文详细介绍了秦时明月6.2魔改版的从零到一部署指南,包括环境准备、服务端安装、安卓客户端配置以及GM后台直通等关键步骤。特别针对安卓客户端配置和GM工具使用提供了实用技巧,帮助用户快速搭建并优化游戏服务器,确保稳定运行。

weixin_42522964的博客 315

SparkCore — stage划分算法源码分析

DAGscheduler中的stage划分源码分析   在之前的文章中,已经分析了stage的划分算法,这里我们到源码里面去看划分算法是怎么实现的。   首先找到提交Job的入口(从action操作开始,找到action操作的runJob -> dagScheduler.runJob -> submitJob -> eventProcessLoop.JobSubmitted -&...

zlx_code的专栏 438

信道估计之MMSE算法

信道估计之MMSE算法前言MMSE估计的原理总结 前言        前篇分析了LS信道估计算法,也说明了由于没有考虑SNR的影响,所以LS算法不适合在低信噪比的情况下使用。本篇来学习信道估计的另外一种常用的算法–MMSE。        为什么说LS没有考虑噪声大小的情况呢,因为LS算法使用的是实际观测量与估计观测量的误差,这并不能精确的代表估计量的真值与估计值的误

大白的博客 2万+

GaussDB本地安装手册(主备模式)

如果实例状态是Normal,则安装成功。三节点集中式配置文件。

Sebastien23的博客 2633

Spark技术内幕:Stage划分及提交源码分析

在一个RDD触发了一个action(比如count,collect)时,任务是如何被提交到?什么是Stage?DAGScheduler的作用是什么?它是如何划分Stage的?本文将基于源码,进行深入分析。

anzhsoft的技术专栏 2万+

【C语言】程序员筑基功法——《函数栈帧的创建与销毁》

汇编角度带你走进函数栈帧

StackFrame 3660

Spark2.4.0源码分析之WorldCount Stage划分(DAGScheduler)(四) ...

Spark2.4.0源码分析之WorldCount Stage划分(DAGScheduler)(四) 更多资源 github: https://github.com/opensourceteams/spark-scala-maven-2.4.0 时序图 https://github.com/opensourceteams/spark-scala-ma...

测试0901-1 196

基于STC8A8K64S4A12的掉电唤醒定时器应用,极大降低产品功耗

通过合理的配置和编程,我们可以充分发挥单片机的功能,实现能效优化和电池寿命延长的目标。其中,掉电唤醒定时器是其一项重要功能,可以在系统处于睡眠状态时通过定时器的计时功能进行唤醒,从而实现对系统功耗的有效控制。使用STC8A8K64S4A12的掉电唤醒定时器功能,我们可以在不影响系统正常工作的情况下,大大降低产品的功耗。通过以上的代码,我们实现了一个简单的掉电唤醒定时器功能。当系统进入睡眠模式后,定时器开始计时,到达预设的唤醒时间后,定时器中断被触发,系统从睡眠模式唤醒,执行相应的操作。

CodeSageX的博客 1090

廖雪峰Python教程[完整版]

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

Spark — stage划分算法原理分析,加上图形展示,详细的说明了stage的划分

DAGScheduler的stage分配算法原理分析 为了直观的描述DAGScheduler的划分算法,我们使用上一篇分析Job触发原理的wordcount程序示例来进行分析,具体代码请看上一篇博客:Spark源码分析之 — Job触发流程原理与源码分析 如下图所示,清晰的演示了stage是如何划分的: 如上所示,DAGScheduler的stage划分算法,会从触发action操作的那...

zlx_code的专栏 1062

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Spark源码分析之DAGScheduler以及stage的划分

Spark源码分析之DAGScheduler以及stage的划分

happy19870612's blog 1078

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

spark 源码分析之十九 -- DAG的生成和Stage的划分

上篇文章spark 源码分析之十八 -- Spark存储体系剖析重点剖析了 Spark的存储体系。从本篇文章开始,剖析Spark作业的调度和计算体系。 在说DAG之前,先简单说一下RDD。 对RDD的整体概括 文档说明如下: RDD全称Resilient Distributed Dataset,即分布式弹性数据集。它是Spark的基本抽象,代表不可变的可分区的可并行计算的...

weixin_30668887的博客 412
上一篇: Spark任务调度策略/资源分配
下一篇: 客户端和NameNode、DataNode通信过程
K. Bob
博客等级 码龄8年 82粉丝 294原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值