文章目录

  • Spark基础介绍
  • 基本概念
  • Spark架构
  • 1.Spark资源分配策略
  • 粗粒度资源分配
  • 细粒度资源分配
  • 资源调度流程
  • 2.Spark任务调度策略
  • 任务调度流程
  • 任务调度算法
  • Task失败重试与推测执行
  • 3.Yarn任务与资源调度流程
  • Yarn基本概念
  • Yarn资源与任务调度流程
  • SparkOnYarn架构
  • Yarn调度算法分类


Spark基础介绍

基本概念

Spark内部有若干术语(Executor、Job、Stage、Task、Driver、DAG等),需要理解并搞清其内部关系,因为这是性能调优的基石。
节点类型有:
1. Master 节点: 常驻master进程,负责管理全部worker节点。
2. Worker 节点: 常驻worker进程,负责管理executor 并与master节点通信。

Dirvier:官方解释为: The process running the main() function of the application and creating the SparkContext。即理解为用户自己编写的应用程序

Executor:执行器:
  在每个Worker节点上为某应用启动的一个进程,该进程负责运行任务,并且负责将数据存在内存或者磁盘上,每个job都有各自独立的Executor。
  Executor是一个执行Task的容器。它的主要职责是:
  1、初始化程序要执行的上下文SparkEnv,解决应用程序需要运行时的jar包的依赖,加载类。
  2、同时还有一个ExecutorBackend向cluster manager汇报当前的任务状态,有点类似hadoop的tasktracker和task。
  也就是说,Executor是一个应用程序运行的监控和执行容器。Executor的数目可以在submit时,由 --num-executors (on yarn)指定.

Job:  
  包含很多task的并行计算,可以认为是Spark RDD 里面的action,每个action算子的执行会生成一个job。
  用户提交的Job会提交给DAGScheduler,Job会被分解成Stage和Task。
Stage:  
  一个Job会被拆分为多组Task,每组任务被称为一个Stage就像Map Stage, Reduce Stage。
  Stage的划分简单来说是以shuffle和result这两种类型来划分。
  在Spark中有两类task,一类是shuffleMapTask,一类是resultTask。第一类task的输出是shuffle所需数据,第二类task的输出是result,stage的划分也以此为依据:shuffle之前的所有变换是一个stage,shuffle之后的操作是另一个stage。例如:
  1) rdd.parallize(1 to 10).foreach(println) 这个操作没有shuffle,直接就输出了,那么只有它的task是resultTask,stage也只有一个;
  2) 如果是rdd.map(x => (x, 1)).reduceByKey(_ + _).foreach(println), 这个job因为有reduce,所以有一个shuffle过程,那么reduceByKey之前的是一个stage,执行shuffleMapTask,输出shuffle所需的数据,reduceByKey到最后是一个stage,直接就输出结果了。
  如果job中有多次shuffle,那么每个shuffle之前都是一个stage。
  spark中会引起shuffle的算子有:
  去重distinct、聚合reduceByKey/groupByKey/xxByKey、排序sortByKey、表关联join、重分区Repartition/Coalesce(shuffle=true)等。
  
Task:
  stage 下的单个任务执行单元。
  一个rdd有多少个partition,就会有多少个task,因为每一个 task 只是处理一个partition上的数据。所以有时为提高执行并行度,使用Repartition或Coalesce(shuffle=true),增多partition数量,从而增多task数量

Spark架构

Spark任务调度、资源调度涉及主要类有
1. SparkContext, DAGSheduler,TaskSheduler -上下文信息,DAG图划分与Stage调度,任务调度
2. ShedulerBackend,CoarseGrainedShedulerBackend,CoarseGrainedExcutorBackend  -与资源管理系统交互
3. ShuffleMapStage,ResultStage,ShuffleMapTask,ResultTask - 划分的Stage和Task类型

1.Spark资源分配策略

粗粒度资源分配

在 Application 执行之前,将所有的资源申请完毕,当资源申请成功后,才会进行任务的调度,当所有的 task 执行完成后,才会释放这部分资源

优点:在 Application 执行之前,所有的资源都申请完毕,每一个task 直接使用资源就可以了,不需要 task 在执行前自己去申请资源,task 启动就快了,task 执行快了,stage 执行就快了,job 就快了,application 执行就快了。

缺点:直到最后一个 task 执行完成才会释放资源,集群的资源无法充分利用。

细粒度资源分配

Application 执行之前不需要先去申请资源,而是直接执行,让 job中的每一个 task 在执行前自己去申请资源,task 执行完成就释放资源。

优点:集群的资源可以充分利用。

缺点:task 自己去申请资源,task 启动变慢,Application 的运行就响应的变慢了。

资源调度流程

启动Master和备用Master(如果是高可用集群需要启动备用Master,否则没有备用Master)。
  2、启动Worker节点。Worker节点启动成功后会向Master注册。在works集合中添加自身信息。
  3、在客户端提交Application,启动spark-submit进程。伪代码:spark-submit --master --deploy-mode cluster --class jarPath
  4、Client向Master为Driver申请资源。申请信息到达Master后在Master的waitingDrivers集合中添加该Driver的申请信息。
  5、当waitingDrivers集合不为空,调用schedule()方法,Master查找works集合,在符合条件的Work节点启动Driver。启动Driver成功后,waitingDrivers集合中的该条申请信息移除。Client客户端的spark-submit进程关闭。
  (Driver启动成功后,会创建DAGScheduler对象和TaskSchedule对象)
  6、当TaskScheduler创建成功后,会向Master会Application申请资源。申请请求发送到Master端后会在waitingApps集合中添加该申请信息。
  7、当waitingApps集合中的元素发生改变,会调用schedule()方法。查找works集合,在符合要求的worker节点启动Executor进程。
  8、当Executor进程启动成功后会将waitingApps集合中的该申请信息移除。并且向TaskSchedule反向注册。此时TaskSchedule就有一批Executor的列表信息。

spark资源调度框架的优缺点 spark 资源调度_大数据

总结:
1) 在默认情况下(没有使用--executor --cores 这个选项)时,每一个 Worker 节点为当前的 Application 只启动一个 Executor,这个 Executor 会使用这个 Worker 管理的所有的cores。(原因:assignedCores(pos) += minCoresPerExecutor);
2) 默认情况下,每个 Executor 使用 1G 内存;
3) 如果想要在一个 Worker 节点启动多个 Executor,需要使--executor --cores 这个选项;
4) spreadOutApps 这个参数可以决定 Executor 的启动方式,默认轮询方式启动,这样有利于数据的本地化。

2.Spark任务调度策略

任务调度流程

spark资源调度框架的优缺点 spark 资源调度_应用程序_02


spark资源调度框架的优缺点 spark 资源调度_spark_03


spark资源调度框架的优缺点 spark 资源调度_spark_04


spark资源调度框架的优缺点 spark 资源调度_应用程序_05

任务调度算法

Spark底层任务调度算法分为两种: FIFO和FAIR
参见https://cloud.tencent.com/developer/article/1198471

Task失败重试与推测执行

Task失败重试与推测执行机制:
 TaskScheduler提交task如果发生了失败,默认会重试三次,如果依然失败,那么则认为这个task就失败了,这时会进行stage重试,DAGScheduler会重新发送TaskSet给TaskScheduler,默认会重试四次,如果四次后依然失败,则认为job失败。因此一个task默认情况下重试3*4=12次
 TaskScheduler不仅能重试失败的task,还会重试straggling(落后,缓慢)task(也就是执行速度比其他task慢太多的task)。如果有运行缓慢的task那么TaskScheduler会启动一个新的task来与这个运行缓慢的task执行相同的处理逻辑。两个task哪个先执行完,就以哪个task的执行结果为准。这就是Spark的推测执行机制。在Spark中推测执行默认是关闭的。推测执行可以通过spark.speculation属性来配置。

3.Yarn任务与资源调度流程

Yarn基本概念

ResourceManager:负责整个集群的资源管理和分配。
ApplicationMaster:YARN中每个Application对应一个AM进程,负责与RM协商获取资源,获取资源后告诉NodeManager为其分配并启动Container。
NodeManager:每个节点的资源和任务管理器,负责启动/停止Container,并监视资源使用情况。
Container:YARN中的抽象资源。

Yarn资源与任务调度流程

yarn-client 模式

yarn-cluster模式:

spark资源调度框架的优缺点 spark 资源调度_spark_06

SparkOnYarn架构

spark资源调度框架的优缺点 spark 资源调度_大数据_07


yarn-cluster模式提交任务,原理如下:

1.Spark Yarn Client向YARN中提交应用程序,包括ApplicationMaster程序、启动ApplicationMaster的命令、需要在Executor中运行的程序等;
    2.ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,其中ApplicationMaster进行SparkContext等的初始化;
    3.ApplicationMaster向ResourceManager注册,这样用户可以直接通过ResourceManage查看应用程序的运行状态,然后它将采用轮询的方式通过RPC协议为各个任务申请资源,并监控它们的运行状态直到运行结束;
    4.一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向ApplicationMaster中的SparkContext注册并申请Task。这一点和Standalone模式一样,只不过SparkContext在Spark Application中初始化时,使用CoarseGrainedSchedulerBackend配合YarnClusterScheduler进行任务的调度,其中YarnClusterScheduler只是对TaskSchedulerImpl的一个简单包装,增加了对Executor的等待逻辑等;
    5.ApplicationMaster中的SparkContext分配Task给CoarseGrainedExecutorBackend执行,CoarseGrainedExecutorBackend运行Task并向ApplicationMaster汇报运行的状态和进度,以让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;
    6.应用程序运行完成后,ApplicationMaster向ResourceManager申请注销并关闭自己;

Yarn调度算法分类

理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源。在Yarn中,负责给应用分配资源的就Scheduler。其实调度本身就是一个难题,很难找到一个完美的策略可以解决所有的应用场景。为此,Yarn提供了多种调度器和可配置的策略供我们选择。
  在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,FairScheduler。

1、FIFO Scheduler

spark资源调度框架的优缺点 spark 资源调度_大数据_08

FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
  FIFO Scheduler是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞。在共享集群中,更适合采用Capacity Scheduler或Fair Scheduler,这两个调度器都允许大任务和小任务在提交的同时获得一定的系统资源。
  从图中可以看出,在FIFO 调度器中,小任务会被大任务阻塞。

2、Capacity Scheduler

spark资源调度框架的优缺点 spark 资源调度_资源分配_09

而对于Capacity调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。

3、Fair Scheduler

spark资源调度框架的优缺点 spark 资源调度_spark资源调度框架的优缺点_10

在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。如下图所示,当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
  需要注意的是,在下图Fair调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成。