Spark 资源调度包 stage 类解析
spark 资源调度包 Stage(阶段) 类解析
Stage 概念
Spark 任务会根据 RDD 之间的依赖关系, 形成一个DAG有向无环图, DAG会被提交给DAGScheduler, DAGSchedular 会把DAG划分为相互依赖的多个stage。
而划分stage的依据就是RDD之间的宽窄依赖。
每个stage包含一个或多个task任务。而这些task以taskSet的形式提交给TaskScheduler运行。
stage是由一组并行的task组成的。
stage计算模式
pipeline 管道设计模式(是一种思想)
由于 RDD 中记录的是 执行的算子(函数)的记录(业务逻辑), 图中的task可以看作是一系列函数的迭代计算, 比如: f4(f3(f2(f1(" ... ")))) <=> 将f1("...") 的结果作为参数传入f2()进行计算, 再将该次计算的结果作为参数传入f3()进行计算......
这种思想其实在线代中很常见, 而scala的高阶函数可以理解为其的一种具体体现。
数据在管道里什么时候数据会落地?
Stage 的 task 并行度是由stage的最后一个RDD的分区数来决定的。
Stage 的 task逻辑不一定都一样
什么操作会改变RDD分区(partition)数?
除repartition外的大多数宽依赖型算子操作大多会改变RDD的分区数
窄依赖算子不会改变RDD的分区数
以下代码验证了pipeline管道设计模式的存在
package com.ronnie.pipeline import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext} object Pipeline {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setMaster("local").setAppName("pipeline")
val sc = new SparkContext(conf)
val rdd: RDD[Int] = sc.parallelize(Array(1,2,3,4))
val rdd01: RDD[Unit] = rdd.map{ x => {println("map ------" + x)}}
val rdd02: RDD[Unit] = rdd01.filter{ x => println("filter ******" + x)
// 返回所有, 不过滤
true
}
rdd02.collect()
sc.stop()
}
}
输出结果:
map ------1
filter ******()
map ------2
filter ******()
map ------3
filter ******()
map ------4
filter ******()
- 可以看到filter总是在map之后执行而不是批量执行map后再批量执行filter
类注释:
/**
* A stage is a set of parallel tasks all computing the same function that need to run as part
* of a Spark job, where all the tasks have the same shuffle dependencies.
* 一个阶段是所有计算相同功能的并行任务集合, 作为spark作业的一部分, 这些任务都有相同的 shuffle 依赖
*
* Each DAG of tasks run by the scheduler is split up into stages at the boundaries where
* shuffle occurs, and then the DAGScheduler runs these stages in topological order.
* 每个由调度器运行的任务的有向无环图在shuffle发生的分界处分化成不同的阶段, 并且这些有向无环图的调度器
* 将以拓扑排序来运行这些 不同阶段的任务
*
* Each Stage can either be a shuffle map stage, in which case its tasks' results are input for
* other stage(s), or a result stage, in which case its tasks directly compute a Spark action
* (e.g. count(), save(), etc) by running a function on an RDD.
* 每个阶段都可以是一个 shuffle 匹配阶段, 该任务的结果可以被其他阶段作为导入, 也可以是 一个结果阶段,
* 它的任务 通过 在RDD上运行 一个公式 来直接计算 一个 spark 行为(计数, 保存等...)
*
* For shuffle map stages, we also track the nodes that each output partition is on.
* 对于 shuffle 匹配阶段, 我们会追踪 每个输出的分区的节点
*
* Each Stage also has a firstJobId, identifying the job that first submitted the stage. When
* FIFO scheduling is used, this allows Stages from earlier jobs to be computed first or
* recovered faster on failure.
* 每个阶段都有一个 首任务Id, 用于辨识第一个提交到该阶段的 任务。 当 先进先出 调度策略被使用时, 这会允
* 许 更早 的 作业 的阶段先被计算, 或者 在失败之后更早的恢复。
*
* Finally, a single stage can be re-executed in multiple attempts due to fault recovery. In
* that case, the Stage object will track multiple StageInfo objects to pass to listeners or \
* the web UI.
* 最终, 由于 容错恢复机制, 单个阶段可以在多次尝试运行中 被重新执行。在这种情况下, 该阶段对象会追踪 许
* 多 阶段信息对象 并 将信息传递给监听者 或者 web UI 界面
*
* The latest one will be accessible through latestInfo.
* 最新的阶段可以通过 最新的信息获取
*
* @param id Unique stage ID id: 唯一的阶段Id
* @param rdd RDD that this stage runs on: for a shuffle map stage, it's the RDD we run map
* tasks on, while for a result stage, it's the target RDD that we ran an action on
* rdd:该 阶段 所运行在的 RDD:对于shuffle匹配阶段, 该RDD是我们 运行匹配任务 所在的RDD, 但对于结果阶
* 段,该RDD是我们运行 行为所在的RDD
* @param numTasks Total number of tasks in stage; 当前阶段的任务数量
* result stages in particular may not need to compute all partitions, e.g. for first(),
* lookup(), and take().
* 结果阶段 实际上不一定需要计算所有分区, 比如使用 first(), lookup() 和 take() 等算子
* @param parents List of stages that this stage depends on (through shuffle dependencies).
* parent: 该阶段 所依赖(shuffle依赖) 的 阶段列表
* @param firstJobId ID of the first job this stage was part of, for FIFO scheduling.
* firstJobId: 该阶段的第一个任务Id, 用于先进先出调度
* @param callSite Location in the user program associated with this stage: either where the
* target RDD was created, for a shuffle map stage, or where the action for a result stage was
* called.
* callSite: 与该阶段相关的用户程序的位置: 对于 shuffle 匹配阶段 是 目标 RDD创建的位置, 对于 结果
* 阶段, 是 行为被调用的位置 (调用位点)
*/
代码:
private[scheduler] abstract class Stage(
val id: Int,
val rdd: RDD[_],
val numTasks: Int,
val parents: List[Stage],
val firstJobId: Int,
val callSite: CallSite)
extends Logging {
// 根据数组长度确定分区数
val numPartitions = rdd.partitions.length /** Set of jobs that this stage belongs to. 该阶段 的任务Id集合*/
val jobIds = new HashSet[Int] /** The ID to use for the next new attempt for this stage.
* 该阶段的下一次新尝试的 Id
*/
private var nextAttemptId: Int = 0
// 短型的调用位点
val name: String = callSite.shortForm
// 长型的调用位点
val details: String = callSite.longForm /**
* Pointer to the [[StageInfo]] object for the most recent attempt.
* 指向阶段信息对象的指针, 用于获取最近最多的尝试
* This needs to be initialized here, before any attempts have actually been created, because
* the DAGScheduler uses this StageInfo to tell SparkListeners when a job starts (which
* happens before any stage attempts have been created).
* 在任何尝试被实际创建之前, 它需要被初始化, 因为 有向无环图的调度器 使用了该阶段信息来告诉spark的监
* 听者有任务启动了(这发生在任何阶段的尝试被发生之前)
*/
private var _latestInfo: StageInfo = StageInfo.fromStage(this, nextAttemptId) /**
* Set of stage attempt IDs that have failed with a FetchFailure.
* 拉取失败的的阶段尝试Id集
* We keep track of these failures in order to avoid endless retries if a stage keeps failing
* with a FetchFailure.
* 我们追踪这些失败时为了防止 一个阶段一直发生拉取失败后 无尽的重试
* We keep track of each attempt ID that has failed to avoid recording duplicate failures if
* multiple tasks from the same stage attempt fail (SPARK-5945).
* 我们追踪失败的每次尝试的Id以防止 如果许多任务在同一个阶段的尝试中失败 会导致 记录重复的失败
*/
val fetchFailedAttemptIds = new HashSet[Int]
// 清除失败Id
private[scheduler] def clearFailures() : Unit = {
fetchFailedAttemptIds.clear()
} /** Creates a new attempt for this stage by creating a new StageInfo with a new attempt ID.
* 通过创建一个新的附带新的尝试Id的状态信息 来为当前阶段创建一个新的尝试
*/
def makeNewStageAttempt(
// 需要计算的分区
numPartitionsToCompute: Int,
// 本地优先的任务
taskLocalityPreferences: Seq[Seq[TaskLocation]] = Seq.empty): Unit = {
// TaskMetrics是内部累加器的一个包装类
val metrics = new TaskMetrics
metrics.register(rdd.sparkContext)
// 获取最近的阶段信息
_latestInfo = StageInfo.fromStage(
this, nextAttemptId, Some(numPartitionsToCompute), metrics, taskLocalityPreferences)
nextAttemptId += 1
} /** Returns the StageInfo for the most recent attempt for this stage.
* 返回最近最多尝试的 当前阶段的 阶段信息
*/
def latestInfo: StageInfo = _latestInfo override final def hashCode(): Int = id override final def equals(other: Any): Boolean = other match {
case stage: Stage => stage != null && stage.id == id
case _ => false
} /** Returns the sequence of partition ids that are missing (i.e. needs to be computed).
* 返回缺失的分区 id 的序列
*/
def findMissingPartitions(): Seq[Int]
}
Spark 资源调度包 stage 类解析的更多相关文章
- [Spark内核] 第31课:Spark资源调度分配内幕天机彻底解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结
本課主題 Master 资源调度的源码鉴赏 [引言部份:你希望读者看完这篇博客后有那些启发.学到什么样的知识点] 更新中...... 资源调度管理 任务调度与资源是通过 DAGScheduler.Ta ...
- 【Spark-core学习之六】 Spark资源调度和任务调度
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...
- tuple解包给类的构造函数
首先我们的第一步当然是将tuple解包.tuple提供了一个get函数来获取第N个元素.例如: get<1>(make_tuple(...)); 要将一个tuple全部拆解,就可以使用通过 ...
- Thrift compiler代码生成类解析
代码生成类解析: Thrift--facebook RPC框架,介绍就不说了,百度,google一大把,使用也不介绍,直接上结构和分析吧. Hello.thrift文件内容如下: namespace ...
- 【Spark篇】---Spark资源调度和任务调度
一.前述 Spark的资源调度是个很重要的模块,只要搞懂原理,才能具体明白Spark是怎么执行的,所以尤其重要. 自愿申请的话,本文分粗粒度和细粒度模式分别介绍. 二.具体 Spark资源调度流程图: ...
- JavaFx 中常见的包和类(javafx笔记 )
JavaFx 中常见的包和类(javafx笔记 ) 更多详细内容请参考<Pro JavaFX 8>. javafx.stage 包包含以下类: Stage 类 Stage 类是任何 J ...
- SpringBoot入门(三)——入口类解析
本文来自网易云社区 上一篇介绍了起步依赖,这篇我们先来看下SpringBoot项目是如何启动的. 入口类 再次观察工程的Maven配置文件,可以看到工程的默认打包方式是jar格式的. <pack ...
- APK包与类更改分析
360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...
- Spark 资源调度 与 任务调度
Spark 资源调度与任务调度的流程(Standalone): 启动集群后, Worker 节点会向 Master 节点汇报资源情况, Master掌握了集群资源状况. 当 Spark 提交一个 Ap ...
随机推荐
- Django的templates(模板)
目录 Django的templates(模板) 模板传值 模板过滤器 模板语法之标签 常用标签之for标签 常用标签之if标签 常用标签之with标签 自定义过滤器和标签 模板的继承和导入 模板的导入 ...
- Day9 - F - Monkey and Banana HDU - 1069
一组研究人员正在设计一项实验,以测试猴子的智商.他们将挂香蕉在建筑物的屋顶,同时,提供一些砖块给这些猴子.如果猴子足够聪明,它应当能够通过合理的放置一些砖块建立一个塔,并爬上去吃他们最喜欢的香蕉. ...
- 虚拟机字节码指令表 JVM
虚拟机字节码指令表 标签(空格分隔): Java基础 JVM 记录虚拟机字节码指令,方便分析.以下内容来自<深入理解Java虚拟机> 字节码 助记符 指令含义 0x00 nop 什么都不做 ...
- 复习hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JDB ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:内容居中
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Linux学习《第五章用户文件权限管理》之补充学习
- DNS 访问 Service【转】
在 Cluster 中,除了可以通过 Cluster IP 访问 Service,Kubernetes 还提供了更为方便的 DNS 访问. kubeadm 部署时会默认安装 kube-dns 组件. ...
- MySQL 错误代码
常见: 1005:创建表失败 1006:创建数据库失败 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1009:不能删除数据库文件导致删除数据库失败 1010:不能删 ...
- String+、intern()、字符串常量池
字符串连接符 "+"及字符串常量池实验.字符串final属性 结果预览 public class StrTest{ public static void main(String[] ...
- java核心-多线程(9)- ThreadLocal类
1.背景 ThreadLocal类我想一般的码农或初级程序员在平时开发中基本上接触不到,但是面试老师会问.往高级点走会遇到这个类.这个类不是为了解决资源的竞争问题,而是为每个线程提供同一个容器 ...