Spark 运行架构及相关概念

一、架构

Spark 框架的核心是一个计算引擎,整体来说,它采用了标准的 master-slave 结构。上图中的 Driver 表示 master ,负责管理整个集群中的作业任务调度;Executor 则是 slave,负责实际执行任务;

1.1 Driver

Spark 驱动器节点,运行 Application 的 main() 函数,负责实际代码的执行工作。它会创建SparkContext,SparkContext 负责和 Cluster Manager 通信,进行资源申请、任务分配和监控等;当 Executor 部分运行完毕后,Driver 负责将 SparkContext 关闭;

Spark 作业执行时主要负责:

  • 将用户程序转化为作业(job)
  • 在 Executor 之间调度任务(task)
  • 跟踪 Executor 的执行情况
  • 通过 UI 展示查询运行情况

1.1.1 SparkContext

SparkContext 是 Spark 功能的主要入口。其代表与 Spark 集群的连接,能够用来在集群上创建 RDD、累加器、广播变量。每个 JVM 里只能存在一个处于激活状态的 SparkContext,在创建新的 SparkContext 之前必须调用 stop() 来关闭之前的 SparkContext。在 SparkContext 的初始化过程中,Spark 会分别创建 DAGScheduler 作业和 TaskScheduler 任务调度两级调度模块。

1.1.1.1 RDD

弹性分布式数据集,是 Spark 的核心结构,Spark 的基本运算单元,可以通过一系列算子进行操作;Spark 的所有算子都是基于 RDD 来执行的,不同的场景会有不同的 RDD 实现类,但是都可以进行相互转换,RDD 执行过程中会形成 DAG 图,然后形成 lineage(血统) 保证容错性;从物理层面来看,RDD 存储的是 block 和 node 之间的映射;RDD 在逻辑上是一个 HDFS 文件,在抽象是一种元素集合,包含了数据。它是可被分区的,分为多个分区,每个分区在集群的不同节点上,从而让 RDD 中的数据可以被并行操作;RDD 有以下特性:

  • 弹性

存储弹性 :内存与磁盘自动切换;

容错弹性 :数据丢失可以自动恢复;

计算弹性 :计算出错有重试机制;

分片弹性:可以根据需要重新分片;

  • 分布式:数据存储在大数据集群不同节点上;
  • 数据集:RDD 封装了计算逻辑,并不保存数据,所以对 RDD 的操作并不会改变数据本身,改变的只是 RDD 提供的数据副本;
  • 数据抽象:RDD 是一个抽象类,需要子类具体实现;
  • 不可变:RDD 可以类似看作 String ,是不可改变的,只能产生新的 RDD;
  • 可分区、并行计算

RDD 的缺陷

  • 不支持细粒度的写和更新操作:Spark 写数据是粗粒度的,所谓粗粒度就是批量写入数据,目的是为了提高效率,但是 Spark 读数据是细粒度的,也就是一条一条读;
  • 不支持增量迭代计算
1.1.1.2 DAG

有向无环图,描述了 RDD 的依赖关系;

有向无环图并不是真正意义的图形,而是由 Spark 程序直接映射成的数据流的高级抽象模型,描述了 RDD 的依赖关系;

当 RDD 遇到 Action 算子时,会将之前的所有算子形成一个 DAG ,也就是 RDD Graph,再在 Spark 中转化为 Job ,提交到集群执行。一个 APP 中可以包含多个 Job;

1.1.1.3 DAGScheduler

DAGScheduler 是 Spark 中高层调度层,它实现了面向阶段的调度。它将 Job 划分成一个或多个 Stage,并把 Stage 分成一个或多个 Task,当完成 Task 的创建后将 Task 按 TaskSet 的方式发送个 TaskScheduler;

如果某个阶段的任务失败,DAGScheduler 会重新提交该阶段。如果某个阶段丢失了,它会重新提交该阶段以及所有依赖的阶段;

DAGScheduler 的工作流程

  1. 提交作业:当用户在程序中调用一个行动操作(如 count、save 等)时,Spark 会创建一个作业并提交给 DAGScheduler。

  2. 划分阶段:DAGScheduler 从最终的 RDD 出发,逆向遍历 RDD 的依赖链,遇到宽依赖就划分一个新的阶段。这样会得到一个或多个阶段,每个阶段包含一系列连续的窄依赖转换。

  3. 提交阶段:DAGScheduler 按照阶段的依赖关系依次提交阶段。如果一个阶段依赖的父阶段已经执行完成,那么该阶段就可以提交了。DAGScheduler 会为每个阶段创建一个任务集(TaskSet),每个任务对应一个分区。然后,DAGScheduler 将这个任务集提交给 TaskScheduler。

  4. 任务调度与执行:TaskScheduler 负责将任务分配到集群的 Executor 上执行。TaskScheduler 会考虑数据本地性,尽量将任务分配到数据所在的节点上。

  5. 监控任务执行:DAGScheduler 监控任务的执行情况。如果某个任务失败,DAGScheduler 会重试该任务(重试次数可配置)。如果重试次数用尽,或者阶段因 shuffle 数据丢失而无法计算,DAGScheduler 会重新提交该阶段以及所有依赖的阶段。

  6. 作业完成:当所有阶段都成功执行完毕后,作业完成。

1.1.1.4 TaskScheduler

TaskScheduler 是 Spark 中负责将 DAGScheduler 划分出来的 TaskSet(一组任务)调度到集群上的组件。负责接收 DAGScheduler 提交来的 TaskSet,按照一定的调度策略将任务分发到 Executor 上执行,并处理任务失败的情况。

1.1.1.5 SparkEnv

Spark 执行环境对象,其中包括与众多 Executor 指向相关的对象;

1.2 Cluster Manager

ClusterManager 是 Spark 资源管理系统的核心组件,负责分配和管理集群资源。standalone 模式中即 Master 节点,控制整个集群;yarn 模式中则是 JobManager;

1.2.1 工作流程

  1. 提交应用程序 :用户通过 spark-submit 提交应用程序;

  2. 资源请求:Driver 向 ClusterManager 请求资源;

  3. 启动 Executor:ClusterManager 在 Worker 节点上启动 Executor 进程;

  4. 任务执行:Driver 将任务发送到 Executor 执行;

  5. 资源释放:应用程序完成后,释放资源;

1.3 Worker

Spark 的计算节点;

1.3.1 Executor

集群中 Worker 节点上一个执行 Application 的 JVM 进程,负责在 Spark 作业中运行具体任务(Task),任务彼此之间相互独立,并负责将数据存在内存或磁盘上,每个 Application 都有各自独立的一批 Executor;

Spark 应用启动时,Executor 节点被同时启动,并且始终伴随着整个 Spark 应用的生命周期而存在。如果有 Executor 节点发生了故障或崩溃,Spark 应用也可以继续执行,会将出错节点上的任务调度到其他 Executor 节点上继续运行;

Executor 的两个核心功能

  • 负责运行组成 Spark 应用的任务,并将结果返回给 Driver 进程
  • 它们通过自身的块管理器(Block Manager)为用户程序中要求缓存的 RDD 提供内存式存储。RDD 是直接缓存在 Executor 进程内的,因此任务可以在运行时充分利用缓存数据加速运算;

二、相关概念

2.1 Job

一个 RDD Graph 触发的作业,包含多个 Task 组成的并行计算,往往由 Spark Action 算子触发,一个 Application 种往往会产生多个 Job,一个 Job 包含多个 RDD 及作用于相应 RDD 上的各种 Operation;在 SparkContext 中通过 runJob() 方法向 Spark 提交 Job;

2.2 Stage

每个 Job 会根据 RDD 的宽依赖关系被切分成多个 Stage,每个 Stage 中包含一组相同的 Task,这一组 Task 也叫 TaskSet;每个 Job 会被拆分成多组 Task,作为一个TaskSet,这个 TaskSet 就称为 Stage;Stage 的划分和调度是由 DAGScheduler 来负责的, Stage 分为最终 Stage(Result Stage) 和非最终的 Stage(Shuffle Map Stage),Stage 的边界就是发生 Shuffle 的地方;

2.3 Task

被送到 Executor上的一个工作单元,一个分区对应一个 Task,Task 执行 RDD 中对应 Stage 中包含的算子。Task 被封装好后放入 Executor 的线程池中执行;Task的调度和管理是由 TaskScheduler 负责;

一个 Job 包含多个 Stage,一个 Stage 包含多个 Task;

2.4 宽依赖和窄依赖

窄依赖和宽依赖的概念主要用在两个地方:

  • 一个是容错中相当于 Redo 日志的功能;
  • 另一个是在调度中构建 DAG 作为不同 Stage 的划分点;

2.4.1 宽依赖

即 shuffle 依赖,指父 RDD 的每个 Partition 都可能被多个子 RDD Partition 使用,子 RDD Partition 通常对应所有的父 RDD Partition;

宽依赖的函数有 groupByKey、join(父 RDD 一个分区的数据进入到多个不同子 RDD 的分区)、partitionBy;

宽依赖的作用

划分 Stage 的依据,对于宽依赖,必须等到上一阶段的计算完成才能计算下一阶段;

2.4.2 窄依赖

窄依赖表示每一个父 RDD 的 Partition 最多被子 RDD 的一个 Partition 使用,

窄依赖我们形象的比喻为独生子女;

2.5 Spark 容错机制

2.5.1 lineage(血统容错)机制

如果一节点死机了,而且运算窄依赖,则只要把丢失的父 RDD 分区重新计算即可,不依赖与其他节点,没有数据计算冗余适合用于窄依赖关系。而宽依赖需要父 RDD 的所有分区都存在,重算数据的开销就很大,并且有冗余计算(问题节点的每个父 RDD 分区并不是都给丢失的子 RDD,但数据也会计算)。

2.5.2 checkpoint 机制

辅助 lineage 做容错,lineage 过长会造成容错成本过高,这样不如在中间点做检查点容错,如果之后有节点出现问题而丢失分区,从做检查点的 RDD 开始重新做 lineage,可以减少开销。

应用场景:

  • DAG 中 lineage 过长;
  • 在宽依赖上做 checkpoint 获得的收益更大;

三、程序提交流程

大致的流程如下图所示:

3.1 Yarn client 模式

  1. 在 Yarn client 模式下,通过 spark-submit 提交程序后,会在 client 服务器运行 main() 函数,启动 Dirver 进程;
  2. Driver 开始构建并初始化 SparkContext ;
  3. SparkContext 向 ClusterManager(ResourceManager)注册,并申请运行 Executor 的资源(内核和内存);
  4. ClusterManager 根据 SparkContext 提出的申请和 Worker(NodeManager) 的心跳报告,来决定在哪个 Worker 上启动 Executor;
  5. Worker 节点收到请求后会启动 Executor;
  6. Executor 向 SparkContext 注册,这样 Driver 就知道哪些 Executor 运行该应用;
  7. SparkContext 构建 DAG 图,DAG Scheduler 将 DAG 图分解成多个 Stage ,并把每个 Stage 的 TaskSet 发送给 Task Scheduler ;
  8. Executor 向 SparkContext 申请 Task ,Task Secheduler 将 Task发送给 Executor,同时 SparkContext 将程序代码发送给 Executor;
  9. Task 在 Executor 上运行,把运行结果反馈给 Task Scheduler,然后再反馈给 DAG Scheduler,运行完毕后写入数据;
  10. SparkContext 向 ClusterManager 注销并释放所有资源;

3.2 Yarn cluster 模式

  1. 在 Yarn cluster 模式下,通过 spark-submit 提交任务后,会启动一个临时进程;
  2. 临时进程向 ClusterManager(ResourceManager) 通信申请启动 ApplicationMaster(Driver);
  3. ClusterManager分配 container,并通知 NodeManager 启动 ApplicationMaster,此时的 ApplicationMaster 就是 Driver;
  4. NodeManager 启动 Driver;
  5. Driver 启动后开始运行用户 main() 函数;
  6. Driver开始构建 SparkContext;
  7. SparkContext 向 ClusterManager注册 Application 并申请运行 Executor 的资源;
  8. ClusterManager收到 Driver 的资源申请后会分配合适的 Worker 节点;
  9. Worker 节点启动 Executor 进程;
  10. Executor 进程启动后会向 SparkContext 反向注册;
  11. SparkContext 构建 DAG 图,DAG Scheduler 将 DAG 图分解成多个 Stage ,并把每个 Stage 的 TaskSet 发送给 Task Scheduler ;
  12. Executor 向 SparkContext 申请 Task ,Task Secheduler 将 Task发送给 Executor,同时 SparkContext 将程序代码发送给 Executor;
  13. Task 在 Executor 上运行,把运行结果反馈给 Task Scheduler,然后再反馈给 DAG Scheduler,运行完毕后写入数据;
  14. SparkContext 向 ClusterManager 注销并释放所有资源;
相关推荐
Jerry952706281 小时前
3.集群与分布式
分布式·架构·架构师·软考·高性能·高可用·架构设计师
beijingliushao1 小时前
101-Spark之Standalone环境安装步骤
大数据·分布式·spark
拓端研究室1 小时前
赢战2025电商新趋势下的增长策略报告:平台格局、跨境趋势、大促消费|附600+份报告PDF、数据、可视化模板汇总下载
大数据·pdf
云 祁1 小时前
Spark SQL 深度优化实战指南:从原理到生产的完整方法论
大数据·数据库·分布式·sql·spark
milanyangbo2 小时前
深入解析 Disruptor:从RingBuffer到缓存行填充的底层魔法
java·数据库·后端·架构
知识分享小能手2 小时前
CentOS Stream 9入门学习教程,从入门到精通,CentOS Stream 9 使用 LNMP 架构部署网站 —— 语法详解与实战案例(12)
学习·架构·centos
BJ_Bonree2 小时前
数智先锋 | 博睿数据×海尔消费金融:破解高频并发与强监管难题!
大数据·人工智能·金融
攻城狮7号2 小时前
AI时代的工业数据心脏:如何选择真正面向未来的时序数据库?
大数据·人工智能·时序数据库·apache iotdb·ainode·iotdb mcp
Jackyzhe2 小时前
Flink学习笔记:状态后端
大数据·flink