Application: 基于Spark的用用户程序,包含了Driver程序和集群上的Executor.
Driver Program: 运行行main函数并且新建SparkContext的程序.
Cluster Manager: 在集群上获取资源的外部服务(例如:standalone,Mesos,Yarn ).
Worker Node:集群中任何可以运行行应用用代码的节点.
Executor: 是在一一个Worker Node上为某应用用启动的一一个进程,该进程负责运行行任务,并且负责将数据存在内存或者磁盘上。每个应用用都有各自自独立立的executors.
Task:被送到某个executor上的工工作单元.
Job:包含很多任务的并行行计算,可以看做和Spark的action对应.
Stage:一一个Job会被拆分很多组任务,每组任务被称为Stage(就像Mapreduce分map任务和reduce任务一一样).
Spark运行主要分为三部分:RDD的创建和转换,DAGScheduler划分任务并生成TaskSet,TaskScheduler将任务调度给Worker运行。
具体的分为下面四个过程, 可以结合图 2一起看, 这部分主要来自这篇骗博客, 这篇博客有例子,很详细,:
(1) SparkContext(RDD相关操作): 在这个过程, 每次转换(transform)会创建一个新的RDD.
→通过(提交RDD集合)
(2) DAGScheduler(遍历RDD拆分Stage,生成作业):这个过程会创建执行计划,Spark 会尽可能地管道化, 并基于是否要重新组织数据来划分阶段 (Stage).
→通过(提交任务集TaskSet)
(3) TaskScheduler: (任务调度管理):这个过程调度任务, 将各阶段划分成不同的任务(Task), 每个任务都是数据和计算的合体, 在进行下一阶段前, 当前阶段的所有任务都要执行完成, 因为下一阶段的第一个转换一定是重新组织数据的, 所以必须等当前阶段所有结果数据都计算出来了才能继续.
→通过(按照资源获取任务)
(4) TaskSetManager: (任务调度管理)
Task管理和序列化:
Task的运行要解决的问题不外乎就是如何以正确的顺序, 有效地管理和分派任务. 如何将Task及运行所需相关数据有效地发送到远端,以及收集运行结果
Task的调度源起于DAGScheduler调用TaskScheduler.submitTasks将一个Stage相关的任务集合(TaskSet)一起提交给TaskScheduler调度.
TaskSchedulerImpl是TaskSchedulerImpl的实现,在TaskSchedulerImpl中, 这一组Task被交给一个新的TaskSetManager实例进行管理, 所有的TaskSetManager经由SchedulableBuilder根据特定的调度策略进行排序,
TaskSchedulerImpl的resourceOffers函数中,当前被选择的TaskSetManager的ResourceOffer函数被调用并返回包含了序列化任务数据的TaskDescription,最后这些TaskDescription再由SchedulerBackend派发到ExecutorBackend去执行
序列化的过程中,App依赖文件相关属性URL等通过DataOutPutStream写出,而Task本身通过可配置的Serializer来序列化,当前可配制的Serializer包括如JavaSerializer ,KryoSerializer等
Task的运行结果在Executor端被序列化并发送回SchedulerBackend,由于受到Akka Frame Size尺寸的限制,如果运行结果数据过大,结果会存储到BlockManager中,这时候发送到SchedulerBackend的是对应数据的BlockID,TaskScheduler最终会调用TaskResultGetter在线程池中以异步的方式读取结果,TaskSetManager再根据运行结果更新任务状态(比如失败重试等)并汇报给DAGScheduler等
图 2 任务调度过程