Spark Runtime里的主要层次分析,梳理Runtime组件和运行流程,

DAGScheduler

Job=多个stage,Stage=多个同种task, Task分为ShuffleMapTask和ResultTask,Dependency分为ShuffleDependency和NarrowDependency

面向stage的切分,切分依据为宽依赖

维护waiting jobs和active jobs。维护waiting stages、active stages和failed stages,以及与jobs的映射关系

主要职能

  1. 接收提交Job的主入口。submitJob(rdd, ...)runJob(rdd, ...)。在SparkContext里会调用这两个方法。

    • 生成一个Stage并提交,接着推断Stage是否有父Stage未完毕,若有。提交并等待父Stage。以此类推。结果是:DAGScheduler里添加了一些waiting stage和一个running stage。
    • running stage提交后。分析stage里Task的类型,生成一个Task描写叙述,即TaskSet。

    • 调用TaskScheduler.submitTask(taskSet, ...)方法,把Task描写叙述提交给TaskScheduler。TaskScheduler依据资源量和触发分配条件,会为这个TaskSet分配资源并触发运行。
    • DAGScheduler提交job后。异步返回JobWaiter对象。能够返回job运行状态,能够cancel job,运行成功后会处理并返回结果
  2. 处理TaskCompletionEvent
    • 假设task运行成功,相应的stage里减去这个task。做一些计数工作:

      • 假设task是ResultTask,计数器Accumulator加一。在job里为该task置true,job finish总数加一。

        加完后假设finish数目与partition数目相等。说明这个stage完毕了,标记stage完毕。从running stages里减去这个stage,做一些stage移除的清理工作

      • 假设task是ShuffleMapTask。计数器Accumulator加一,在stage里加上一个output location。里面是一个MapStatus类。MapStatusShuffleMapTask运行完毕的返回,包含location信息和block size(能够选择压缩或未压缩)。同一时候检查该stage完毕,向MapOutputTracker注冊本stage里的shuffleId和location信息。然后检查stage的output location里是否存在空。若存在空。说明一些task失败了,整个stage又一次提交;否则,继续从waiting stages里提交下一个须要做的stage
    • 假设task是重提交,相应的stage里添加这个task
    • 假设task是fetch失败,立即标记相应的stage完毕。从running stages里减去。

      假设不同意retry。abort整个stage;否则,又一次提交整个stage。

      另外,把这个fetch相关的location和map任务信息。从stage里剔除,从MapOutputTracker注销掉。最后,假设这次fetch的blockManagerId对象不为空,做一次ExecutorLost处理,下次shuffle会换在还有一个executor上去运行。

    • 其它task状态会由TaskScheduler处理,如Exception, TaskResultLost, commitDenied等。

  3. 其它与job相关的操作还包含:cancel job, cancel stage, resubmit failed stage等

其它职能

1. cacheLocations 和 preferLocation

private val cacheLocs = new HashMap[Int, Array[Seq[TaskLocation]]]

TaskScheduler

维护task和executor相应关系,executor和物理资源相应关系。在排队的task和正在跑的task。

内部维护一个任务队列。依据FIFO或Fair策略,调度任务。

TaskScheduler本身是个接口,spark里仅仅实现了一个TaskSchedulerImpl。理论上任务调度能够定制。以下是TaskScheduler的主要接口:

def start(): Unit
def postStartHook() { }
def stop(): Unit
def submitTasks(taskSet: TaskSet): Unit
def cancelTasks(stageId: Int, interruptThread: Boolean)
def setDAGScheduler(dagScheduler: DAGScheduler): Unit
def executorHeartbeatReceived(execId: String, taskMetrics: Array[(Long, TaskMetrics)],
blockManagerId: BlockManagerId): Boolean

主要职能

  1. submitTasks(taskSet),接收DAGScheduler提交来的tasks

    • 为tasks创建一个TaskSetManager,加入到任务队列里。

      TaskSetManager跟踪每一个task的运行状况,维护了task的很多详细信息。

    • 触发一次资源的索要。
      • 首先。TaskScheduler对比手头的可用资源和Task队列。进行executor分配(考虑优先级、本地化等策略),符合条件的executor会被分配给TaskSetManager
      • 然后。得到的Task描写叙述交给SchedulerBackend。调用launchTask(tasks)。触发executor上task的运行。

        task描写叙述被序列化后发给executor,executor提取task信息。调用task的run()方法运行计算。

  2. cancelTasks(stageId),取消一个stage的tasks
    • 调用SchedulerBackendkillTask(taskId, executorId, ...)方法。

      taskId和executorId在TaskScheduler里一直维护着。

  3. resourceOffer(offers: Seq[Workers]),这是很重要的一个方法,调用者是SchedulerBacnend,用途是底层资源SchedulerBackend把空余的workers资源交给TaskScheduler。让其依据调度策略为排队的任务分配合理的cpu和内存资源。然后把任务描写叙述列表传回给SchedulerBackend
    • 从worker offers里。搜集executor和host的相应关系、active executors、机架信息等等
    • worker offers资源列表进行随机洗牌,任务队列里的任务列表依据调度策略进行一次排序
    • 遍历每一个taskSet,依照进程本地化、worker本地化、机器本地化、机架本地化的优先级顺序,为每一个taskSet提供可用的cpu核数,看是否满足
      • 默认一个task须要一个cpu。设置參数为"spark.task.cpus=1"
      • 为taskSet分配资源,校验是否满足的逻辑,终于在TaskSetManagerresourceOffer(execId, host, maxLocality)方法里
      • 满足的话,会生成终于的任务描写叙述。而且调用DAGSchedulertaskStarted(task, info)方法。通知DAGScheduler,这时候每次会触发DAGScheduler做一次submitMissingStage的尝试,即stage的tasks都分配到了资源的话,立即会被提交运行
  4. statusUpdate(taskId, taskState, data),还有一个很重要的方法,调用者是SchedulerBacnend,用途是SchedulerBacnend会将task运行的状态汇报给TaskScheduler做一些决定
    • TaskLost,找到该task相应的executor。从active executor里移除。避免这个executor被分配到其它task继续失败下去。

    • task finish包含四种状态:finished, killed, failed, lost。仅仅有finished是成功运行完毕了。

      其它三种是失败。

    • task成功运行完,调用TaskResultGetter.enqueueSuccessfulTask(taskSet, tid, data),否则调用TaskResultGetter.enqueueFailedTask(taskSet, tid, state, data)TaskResultGetter内部维护了一个线程池,负责异步fetch task运行结果并反序列化。默认开四个线程做这件事,可配參数"spark.resultGetter.threads"=4

TaskResultGetter取task result的逻辑

  • 对于success task。假设taskResult里的数据是直接结果数据。直接把data反序列出来得到结果。假设不是。会调用blockManager.getRemoteBytes(blockId)从远程获取。

    假设远程取回的数据是空的,那么会调用TaskScheduler.handleFailedTask,告诉它这个任务是完毕了的可是数据是丢失的。

    否则。取到数据之后会通知BlockManagerMaster移除这个block信息,调用TaskScheduler.handleSuccessfulTask。告诉它这个任务是运行成功的。而且把result data传回去。

  • 对于failed task。从data里解析出fail的理由,调用TaskScheduler.handleFailedTask。告诉它这个任务失败了,理由是什么。

SchedulerBackend

TaskScheduler下层。用于对接不同的资源管理系统,SchedulerBackend是个接口。须要实现的主要方法例如以下:

def start(): Unit
def stop(): Unit
def reviveOffers(): Unit // 重要方法:SchedulerBackend把自己手头上的可用资源交给TaskScheduler。TaskScheduler依据调度策略分配给排队的任务吗,返回一批可运行的任务描写叙述,SchedulerBackend负责launchTask,即终于把task塞到了executor模型上,executor里的线程池会运行task的run()
def killTask(taskId: Long, executorId: String, interruptThread: Boolean): Unit =
throw new UnsupportedOperationException

粗粒度:进程常驻的模式。典型代表是standalone模式,mesos粗粒度模式,yarn

细粒度:mesos细粒度模式

这里讨论粗粒度模式,更好理解:CoarseGrainedSchedulerBackend

维护executor相关信息(包含executor的地址、通信端口、host、总核数。剩余核数),手头上executor有多少被注冊使用了。有多少剩余,总共还有多少核是空的等等。

主要职能

  1. Driver端主要通过actor监听和处理以下这些事件:

    • RegisterExecutor(executorId, hostPort, cores, logUrls)。这是executor加入的来源,通常worker拉起、重新启动会触发executor的注冊。CoarseGrainedSchedulerBackend把这些executor维护起来,更新内部的资源信息。比方总核数添加。最后调用一次makeOffer(),即把手头资源丢给TaskScheduler去分配一次。返回任务描写叙述回来。把任务launch起来。

      这个makeOffer()的调用会出如今不论什么与资源变化相关的事件中,以下会看到。

    • StatusUpdate(executorId, taskId, state, data)。task的状态回调。首先,调用TaskScheduler.statusUpdate上报上去。然后。推断这个task是否运行结束了。结束了的话把executor上的freeCore加回去,调用一次makeOffer()
    • ReviveOffers

      这个事件就是别人直接向SchedulerBackend请求资源,直接调用makeOffer()

    • KillTask(taskId, executorId, interruptThread)。这个killTask的事件。会被发送给executor的actor,executor会处理KillTask这个事件。
    • StopExecutors。通知每一个executor,处理StopExecutor事件。

    • RemoveExecutor(executorId, reason)。从维护信息中,那这堆executor涉及的资源数减掉。然后调用TaskScheduler.executorLost()方法,通知上层我这边有一批资源不能用了,你处理下吧。

      TaskScheduler会继续把executorLost的事件上报给DAGScheduler,原因是DAGScheduler关心shuffle任务的output location。

      DAGScheduler会告诉BlockManager这个executor不可用了,移走它,然后把全部的stage的shuffleOutput信息都遍历一遍,移走这个executor,而且把更新后的shuffleOutput信息注冊到MapOutputTracker上,最后清理下本地的CachedLocationsMap。

  2. reviveOffers()方法的实现。

    直接调用了makeOffers()方法,得到一批可运行的任务描写叙述。调用launchTasks

  3. launchTasks(tasks: Seq[Seq[TaskDescription]])方法。
    • 遍历每一个task描写叙述。序列化成二进制。然后发送给每一个相应的executor这个任务信息

      • 假设这个二进制信息太大,超过了9.2M(默认的akkaFrameSize 10M 减去 默认 为akka留空的200K)。会出错,abort整个taskSet。并打印提醒增大akka frame size
      • 假设二进制数据大小可接受,发送给executor的actor。处理LaunchTask(serializedTask)事件。

Executor

Executor是spark里的进程模型。能够套用到不同的资源管理系统上。与SchedulerBackend配合使用。

内部有个线程池,有个running tasks map,有个actor,接收上面提到的由SchedulerBackend发来的事件。

事件处理

  1. launchTask

    依据task描写叙述。生成一个TaskRunner线程,丢尽running tasks map里。用线程池运行这个TaskRunner

  2. killTask。从running tasks map里拿出线程对象,调它的kill方法。

全文完 :)

Spark Core Runtime分析: DAGScheduler, TaskScheduler, SchedulerBackend的更多相关文章

  1. spark 源码分析之四 -- TaskScheduler的创建和启动过程

    在 spark 源码分析之二 -- SparkContext 的初始化过程 中,第 14 步 和 16 步分别描述了 TaskScheduler的 初始化 和 启动过程. 话分两头,先说 TaskSc ...

  2. Spark Core源代码分析: Spark任务运行模型

    DAGScheduler 面向stage的调度层,为job生成以stage组成的DAG,提交TaskSet给TaskScheduler运行. 每个Stage内,都是独立的tasks,他们共同运行同一个 ...

  3. Spark源码分析 – DAGScheduler

    DAGScheduler的架构其实非常简单, 1. eventQueue, 所有需要DAGScheduler处理的事情都需要往eventQueue中发送event 2. eventLoop Threa ...

  4. Spark Core源代码分析: RDD基础

    RDD RDD初始參数:上下文和一组依赖 abstract class RDD[T: ClassTag]( @transient private var sc: SparkContext, @tran ...

  5. Spark Core源代码分析: Spark任务模型

    概述 一个Spark的Job分为多个stage,最后一个stage会包含一个或多个ResultTask,前面的stages会包含一个或多个ShuffleMapTasks. ResultTask运行并将 ...

  6. spark源码分析以及优化

    第一章.spark源码分析之RDD四种依赖关系 一.RDD四种依赖关系 RDD四种依赖关系,分别是 ShuffleDependency.PrunDependency.RangeDependency和O ...

  7. 【Spark Core】任务运行机制和Task源代码浅析1

    引言 上一小节<TaskScheduler源代码与任务提交原理浅析2>介绍了Driver側将Stage进行划分.依据Executor闲置情况分发任务,终于通过DriverActor向exe ...

  8. Spark源码分析 – 汇总索引

    http://jerryshao.me/categories.html#architecture-ref http://blog.csdn.net/pelick/article/details/172 ...

  9. spark 源码分析之十九 -- Stage的提交

    引言 上篇 spark 源码分析之十九 -- DAG的生成和Stage的划分 中,主要介绍了下图中的前两个阶段DAG的构建和Stage的划分. 本篇文章主要剖析,Stage是如何提交的. rdd的依赖 ...

随机推荐

  1. 未知高度的图片在div设置垂直居中

    方法一: 该方法是将外部容器的显示模式设置成display:table,img标签外部再嵌套一个span标签,并设置span的显示模式为display:table-cell,这样就可以很方便的使用ve ...

  2. 【记录】cygwin下折腾个人配置环境

    (本文由hcbbt发布,转载请注明出处,blog.csdn[dot]net/hcbbT)      cygwin是windows下的linux的模拟环境,不仅可以执行linux的各种命令,可以在cyg ...

  3. HDU 1495 很可乐 (DFS)

    题目链接:很可乐 解析:一个瓶子,容量为s.两个杯子,容量分别为n和m,问最少多少次倾倒才干将一瓶可乐均分为两份. 直接模拟每次的倾倒.然后递归求解. 能够加个预判的条件,要是s是奇数的时候,不管怎样 ...

  4. jQuery CircleCounter的环形倒计时效果

    在线演示1 本地下载 使用jQuery插件CircleCounter生成的环形倒计时效果,这个插件使用HTML5画布生成动画效果,还不错,大家可以试试! 顺带手录制了个代码,大家不吝赐教:http:/ ...

  5. C#应用视频教程3.4 Halcon+C#测试

    有了前面的基础后,我们来测试一下如何把程序做的更通用,首先是把初始化的方法修改一下,在初始化的时候传递过去HTuple这个对象(改成了全局的变量,以便于不同的方法调用)   其次需要有相机打开/相机关 ...

  6. AsyncTask 和 Thread 区别

    一.AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute().onPostExecute()及更新UI方法 ...

  7. SqlServer 之 用 IP 地址连接数据库报错" 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误 "

    问题描述:       在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接. (p ...

  8. php之快速入门学习-12(超级全局变量)

    PHP 超级全局变量 超级全局变量在PHP 4.1.0之后被启用, 是PHP系统中自带的变量,在一个脚本的全部作用域中都可用. PHP 超级全局变量 PHP中预定义了几个超级全局变量(superglo ...

  9. 3DMax脚本插件--改动材质&amp;贴图名称

    从网上淘到了一套人物的模型,当时的心情是激动无比,掏出用的不熟练的3DMax折腾了半天.突然发现了一个蛋疼的事儿,所有的模型文件,材质名称,子材质,以及贴图所实用的是中文命名!! ! 尽管说是能跑,只 ...

  10. listView.getChildAt(i)时java.lang.NullPointerException

    BaseAdapter返回的是当前屏幕所能显示Item条数的组件,所以通过listView.getChildAt(i); 返回的是当前屏幕所能显示的组件.不能通过listView.getChildAt ...