Spark作业提交流程
spark-submit提交代码,Driver 执行new SparkContext(),在 SparkContext 里构造DAGScheduler和TaskScheduler。- TaskScheduler 会通过后台的一个进程,连接 Master,向 Master 注册 Application。
- Master 接收到 Application 请求后,会使用相应的资源调度算法,在 Worker 上为这个 Application 启动多个 Executer。
- Executor 启动后,会自己反向注册到 TaskScheduler 中。所有 Executor 都注册到 Driver 上之后,SparkContext 结束初始化,接下来往下执行我们自己的代码。
- 每执行到一个 Action,就会创建一个 Job。Job 会提交给 DAGScheduler。
- DAGScheduler 会将 Job划分为多个 stage,然后每个 stage 创建一个 TaskSet。
- TaskScheduler 会把每一个 TaskSet 里的 Task,提交到 Executor 上执行。
- Executor 上有线程池,每接收到一个 Task,就用 TaskRunner 封装,然后从线程池里取出一个线程执行这个 task。(TaskRunner 将我们编写的代码,拷贝,反序列化,执行 Task,每个 Task 执行 RDD 里的一个 partition)
各个组件解释
DAG
有向无环图,描述了 RDD 之间的依赖关系,这种关系也被叫做血缘。DAG 在 Spark 中对应的实现为 DAGScheduler。
Stage
DAGScheduler 会根据 RDD 之间的宽依赖,将 job 划分成多个 stage,每个 stage 包含一个由多个 task 组成的 taskSet。
RDD
弹性分布式数据集,一个 RDD 代表一个可以被分区的只读数据集。一个 RDD 中有一到多个分区,每个分区有多条记录。
特征:
- 宽窄依赖关系,窄依赖的 RDD 可以在同一个 stage 中计算;
- 一个 RDD 会有多个分区,分区的大小决定了这个 RDD 的计算粒度,每个 RDD 的分区的计算都在一个 task 中进行;
- 基于“移动数据不如移动计算”的原则,在任务调度的时候,优先把 job 移动到数据块的位置执行;
- Spark 中的计算都是以分区为基本单位的,compute 函数只是对迭代器进行复合,并不保存单次计算的结果。
- partitioner 只存在于(K,V)类型的 RDD 中,非(K,V)类型的 partitioner 的值就是 None。
Worker
Spark 集群节点上的进程,负责管理节点。
- 在 YARN 部署模式下实际由 NodeManager 替代。Worker 节点主要负责,把自己的内存、CPU 等资源通过注册机制告知 ClusterManager,创建 Executor,把资源和任务进一步分配给 Executor,同步资源信息,Executor 状态信息给 ClusterManager。
- Standalone 部署模式下,Master 将 Worker 上的内存、CPU 以及 Executor 等资源分配给 Application 后,将命令 Worker 启动 CoarseGrainedExecutorBackend 进程(此进程会创建 Executor 实例)。
Excutor
每个 Spark 程序在每个 Worker 上启动的一个进程,与 Spark 程序是一对多的关系,负责在 Spark 节点上启动 task,管理内存和磁盘及与 Worker 和 Driver 的信息同步。如果一个 Spark 节点上有多个程序,那么就会启动多个 Excutor。
Driver
用来运行 Spark 程序的 main 函数,并创建 SparkContext,其目的是为了准备 Spark 程序的执行环境。当 Excutor 执行完毕之后,Driver 负责把 SparkContext 关闭,释放资源。