要真正理解 Spark 的运行机制,首先必须掌握其分布式架构中的关键角色。一个 Spark 应用程序 (Application) 的成功运行,离不开 Driver、Cluster Manager、Worker 和 Executor 等角色的协同工作。本节,我们将深入剖析这些核心角色的职责与相互关系。
一、Spark 应用程序的核心角色
一个完整的 Spark Application 主要由以下几个核心角色构成:
a. Driver (驱动程序)
核心职责: 应用程序的“大脑”。它是整个应用的入口和总指挥。 识别标志: 哪里创建了 SparkContext (或 SparkSession),哪里就是 Driver。 具体工作:

b. Cluster Manager (集群管理器)
核心职责: 集群的“资源管家”。负责管理和分配集群中的物理资源。 不同模式下的实现:
Standalone 模式: 角色是 Master 节点 YARN 模式: 角色是 ResourceManager Kubernetes 模式: 角色是 Kubernetes Master (API Server)

c. Worker Node (工作节点)
核心职责: 集群中的“劳动力”。任何可以运行 Application 计算代码的物理或虚拟机器。 具体工作:

d. Executor (执行器)
核心职责: 任务的“执行单元”。它是一个运行在 Worker Node 上的 JVM 进程 (或可视为一个线程池)。 具体工作:
e. Task (任务)
核心职责: 工作的“最小单位”。一个 Task 是一个被发送到 Executor 的工作单元,通常在一个线程中执行。 具体工作: 对一个 RDD 的一个分区 (Partition) 执行一系列的计算操作 (如 map, filter)。

二、RDD 分区与 Task 的并行执行
要理解 Spark 如何实现并行计算,关键在于理解 RDD 分 和 Task 之间的关系。
RDD (弹性分布式数据集):是 Spark 中最基本的数据抽象。一个 RDD 逻辑上是一个完整的数据集,但物理上被切分成了多个分区,分布在集群的不同节点上。
分区与 HDFS Block 的关系:当我们从 HDFS 读取文件创建 RDD 时,通常情况下,HDFS 中的一个 Block 会对应 RDD 的一个 Partition。例如,一个 300MB 的文件在 HDFS 中被存储为 128MB, 128MB, 44MB 三个 Block,那么通过 sc.textFile() 读取后,生成的 RDD 很可能也会有 3 个分区。
并行计算的核心:Spark 为 RDD 的每一个分区启动一个 Task 来进行计算。如果有 N 个分区,Spark 就可以并行地运行 N 个 Task,从而实现分布式并行计算。

代码执行流程解析: 当我们编写并提交如下代码时:
# … SparkContext 已创建
textRDD = sc.textFile("hdfs://…")
flatmap_RDD = textRDD.flatMap(lambda line: line.split(" "))
mapRDD = flatmap_RDD.map(lambda word:(word,1))
resultRDD = mapRDD.reduceByKey(lambda a,b:a+b)
resultRDD.collect()
sc.textFile(…): 读取数据并创建 RDD,确定分区数。 flatMap, map, reduceByKey: 这些是转换 (Transformation) 操作,它们并不会立即执行,只是记录了 RDD 之间的依赖关系,形成一个有向无环图 (DAG)。 collect(): 这是一个行动 (Action) 操作。它的触发,会让 Driver 将整个 DAG 提交给集群执行。Driver 将计算任务分解为 Task,分发给 Executor。Executor 启动多个 Task 线程,每个线程负责处理一个分区上的数据,并依次执行 flatMap, map, reduceByKey 等一系列计算。
三、Driver 端与 Executor 端的代码执行划分
在一个 Spark Application 中,并非所有代码都在Executor 上执行。理解代码的执行位置对于调试和性能优化至关重要。

执行位置划分:
在 Driver 端执行的代码:
在 Executor 端执行的代码:
四、spark-shell, pyspark, spark-submit 的关系与参数
spark-shell (Scala) 和 pyspark (Python) 是交互式的 Shell 环境,非常适合探索性分析和快速原型开发。而 spark-submit 是用于提交已打包好的独立应用 (JARs or Python scripts) 到集群的通用工具。
核心关系:
spark-shell 和 pyspark 的底层实际上也是调用 spark-submit 来启动一个 Spark 应用的。 因此,所有可以传递给 spark-submit 的配置参数,同样可以在启动 spark-shell 或 pyspark 时使用。
常用 spark-submit 参数解析 (YARN 模式下) 下表总结了一些在 YARN 模式下提交任务时最常用的参数:
| –master | 指定集群管理器。 | local[*] | yarn |
| –deploy-mode | 部署模式 (client 或 cluster)。 | client | cluster |
| –driver-memory | Driver进程的内存。 | 1g | 2g |
| –driver-cores | Driver进程的CPU核心数 (仅限cluster模式)。 | 1 | 2 |
| –num-executors | 启动的Executor数量。 | 2 | 10 |
| –executor-memory | 每个Executor的内存。 | 1g | 4g |
| –executor-cores | 每个Executor的CPU核心数。 | 1 | 4 |
示例命令:提交一个配置丰富的 Spark 作业到 YARN
spark-submit \\
–master yarn \\
–deploy-mode cluster \\
–driver-memory 1g \\
–driver-cores 1 \\
–num-executors 10 \\
–executor-memory 2g \\
–executor-cores 2 \\
–name "MyComplexApp" \\
my_spark_app.py arg1 arg2
资源计算示例解析: 根据上面的命令,我们向 YARN 集群申请了多少资源? Driver 资源: 1g 内存, 1 个 CPU core (运行在某个NodeManager上)。 Executor 总资源:
- 总Executor内存: 10 (executors) * 2g (memory/executor) = 20g
- 总Executor核心数: 10 (executors) * 2 (cores/executor) = 20 cores
整个应用总共需要 1g + 20g = 21g 内存和 1 + 20 = 21 个CPU核心。在提交前,你需要确认 YARN 集群有足够的可用资源</-s>。

日期:2025年10月6日 专栏:Spark教程(PySpark)





