Spark核心概念释义及基本运行流程

一、核心概念释义

Application

基于Spark的用户程序,由集群上的Driver和Executor组成。简单的说,一个Application应用程序可以有多个job多个Stage

 Driver

该进程运行应用程序的main()函数并创建SparkContext,用户编写的应用程序,就是我们打包提交的spark jar

Job

一种由多个操作组成的并行计算任务,这些任务对应一些Spark操作(例如 savecollect );可以在Driver日志中看到job。一个action算子对应一个job,一个job通常由多个stage组成

Stage

每个job都被分为一些较小的任务集,这些任务集就是  stages(类似于MapReduce中的map和reduce阶段),stage是相互依赖的; 后面的Stage依赖于前面的Stage,也就是说只有前面依赖的Stage计算完毕后,后面的Stage才会运行。可以在Driver日志中看到Stage 

Task

发送给某个Executor的工作单元。一个stage对应多个task,task由dirver发送到executor,task运行在executor中

Executor

NM节点上的应用程序启动的进程,该进程运行任务并将数据跨任务存储在内存或磁盘存储中。每个应用程序都有自己的执行程序。

exector运行在woker节点上,exector由dirver在woker节点上申请资源创建,application包括driver program和executors。exector以多线程方式运行Task,在一个Application运行期间,同一exector只属于某一个Application,也就是说exector对于Application是专属的

Container

Container是相对与yarn来说的,ContainerNM中的一个服务,每个Executor会单独占用一个Container,单个Container内存的上限,就是Spark Executor内存上限。就内存而言,Container由spark.yarn.executor.memoryOverhead(off-heap)与spark.executor.memory(on-heap)两部分组成

综上所述,一个application包括driver program和executors,一个application应用可以有多个job组成,一个action算子对应一个job,一般而言,程序中有几个action算子就会产生几个job。一个job可以由多个stage组成,一个stage对应多个task,task由dirver发送到各个executor,task运行在executor中,exector以并行的方式执行task。每个Executor独占一个Container


二、基本运行流程

下图简单呈现了yarn-cluster模式下运行流程

  1. 用户在Client上向集群提交spark应用程序,向RM请求,启动ApplicationMaster

  2. SparkContext 向资源管理器注册并向资源管理器申请运行Executor函数

  3. 资源管理器分配Executor,而后资源管理器启动Executor进程

  4. Executor 发送心跳至资源管理器大数据

  5. SparkContext 构建DAG有向无环图优化

  6. 将DAG分解成Stage(TaskSet)spa

  7. 把Stage发送给TaskScheduler线程

  8. Executor 向 SparkContext 申请 Task

  9. TaskScheduler 将 Task 发送给 Executor 运行

  10. 同时 SparkContext 将应用程序代码发放给 Executor

  11. Task 在 Executor 上运行,运行完毕返回执行结果给Driver,释放全部资源


三、基本流程剖析

1、DAG构建

先看一段伪代码

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(...)

 上述代码的DAG图以下所示:

Spark内核会在须要计算发生的时刻绘制一张关于计算路径的有向无环图,也就是如上图所示的DAG。

Spark的计算发生在RDD的Action算子的操作,而对Action算子以前的所有Transformation算子,Spark只是记录下RDD生成的轨迹,而不会触发真正的计算。上述代码中saveAsTextFile与foreach是Action算子,最终在此触发计算,之前的map、union、join属于Transformation算子,并不会发生真正计算

2、Stage的划分

(1)宽窄依赖

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

回顾下宽窄依赖的划分原则:
窄依赖:父RDD的一个分区只会被子RDD的一个分区依赖。即一对一或者多对一的关系,可理解为独生子女。 常见的窄依赖有:map、filter、union、mapPartitions、mapValues、join(父RDD是hash-partitioned)等。
宽依赖:父RDD的一个分区会被子RDD的多个分区依赖(涉及到shuffle)。即一对多的关系,可理解为超生。 常见的宽依赖有groupByKey、partitionBy、reduceByKey、join(父RDD不是hash-partitioned)等。

(2)回溯算法

宽窄依赖的核心思想就是回溯算法从后往前回溯/反向解析,遇到窄依赖加入本Stage,碰见宽依赖进行Stage切分,产生一个新的Stage。

Spark内核会从触发Action算子的那个RDD开始从后往前推,首先会为最后一个RDD建立一个Stage,而后继续倒推,若是发现对某个RDD是宽依赖,那么就会将宽依赖的那个RDD建立一个新的Stage,那个RDD就是新的Stage的最后一个RDD。
而后依次类推,继续倒推,根据窄依赖或者宽依赖进行Stage的划分,直到全部的RDD所有遍历完成为止。

(3)举例说明

下图展示了DAG划分Stage的过程

一个Spark程序能够有多个DAG(有几个Action,就有几个DAG,上图最后只有一个Action(图中未表现),那么就是一个DAG)

一个DAG能够有多个Stage(根据宽依赖/shuffle进行划分)。

同一个Stage能够有多个Task并行执行(task数=分区数,如上图,Stage1 中有三个分区P1、P2、P3,对应的也有三个 Task)。

能够看到这个DAG中只reduceByKey操做是一个宽依赖,Spark内核会以此为边界将其先后划分红不一样的Stage。

同时咱们能够注意到,在图中Stage1中,从textFile到flatMap到map都是窄依赖,这几步操做能够造成一个流水线操做,经过flatMap操做生成的partition能够不用等待整个RDD计算结束,而是继续进行map操做,这样大大提升了计算的效率

3、提交stage

这些stage最终会被转换成一个个的task集,由DAGScheduler经过TaskScheduler接口分批提交任务集,这个任务集最终会触发TaskScheduler构建一个TaskSetManager的实例来管理这个任务集的生命周期,对于DAGScheduler来讲,提交调度阶段的工做到此就完成了。

而TaskScheduler的具体实现则会在获得计算资源的时候,进一步经过TaskSetManager调度具体的任务到对应的Executor节点上进行运算

参考:Spark底层原理详细解析(深度好文,建议收藏) - 尚码园

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值