本文是大数据系列第 79 篇,系统梳理 Spark Standalone 部署模式的架构设计、作业提交流程和性能优化策略。

完整图文版(含截图):CSDN 原文 | 掘金

Standalone 集群四大组件

Driver

用户程序的”大脑”,负责:

  • 将用户代码解析为 DAG
  • 划分 Stage,生成 Task 列表
  • 向 Master 申请资源
  • 监控 Task 执行状态,处理失败重试

Master

集群资源管理器,默认监听端口 7077,Web UI 端口 8080

  • 维护集群全局资源视图
  • 接受应用注册请求,按策略分配 Worker 资源
  • 持续监控 Worker 心跳,处理节点故障

Worker

每个物理节点运行一个 Worker 进程:

  • 启动时向 Master 注册并上报可用 CPU core 和内存
  • 根据 Master 指令启动/停止 Executor 进程
  • 定期向 Master 发送心跳

Executor

实际执行计算的进程,运行在 Worker 节点上:

  • 维护线程池,并发执行多个 Task
  • 管理本节点的 RDD 数据缓存(BlockManager)
  • 向 Driver 汇报 Task 完成状态

应用提交流程

用户代码(main 方法)


① 初始化 SparkContext


② Driver 向 Master 注册,说明所需资源(core 数、内存大小)


③ Master 校验集群容量,选择合适的 Worker 节点


④ Master 通知 Worker 启动 Executor 进程


⑤ Executor 启动后**反向注册**到 Driver


⑥ Driver 将序列化后的 Task 分发给对应 Executor 执行

SparkContext 内部架构

SparkContext 是驱动端的核心对象,内含三个关键子系统:

组件职责
DAGScheduler将 RDD DAG 按宽依赖切分为 Stage,提交 Stage 给 TaskScheduler
TaskScheduler接收 Stage 中的 TaskSet,按资源和本地性优先级分发 Task
SchedulerBackend与 Executor 通信,处理注册、状态汇报和资源回收

Shuffle 演进历史

Spark 的 Shuffle 实现经历了三代演进:

Hash-Based Shuffle V1(早期)

  • 每个 Map Task 为每个 Reduce Task 创建一个文件
  • 文件数 = Map Task 数 × Reduce Task 数,极易产生数十万小文件
  • 磁盘和文件系统压力巨大

Hash-Based Shuffle V2(文件合并)

  • 同一 Executor 上的多个 Map Task 合并写入同一组文件
  • 文件数降至 Executor 数 × Reduce Task 数
  • 仍存在随机写磁盘问题

Sort-Based Shuffle(Spark 1.2 起默认)

  • 每个 Map Task 只写一个数据文件 + 一个索引文件
  • 数据按分区 ID 排序后顺序写入,磁盘 I/O 效率大幅提升
  • 文件数降至 Map Task 数 × 2,是目前最优实现

RDD 优化策略

1. 避免重复创建同一 RDD

对同一数据源执行两次 textFile 会触发两次读取,应复用同一个 RDD 引用。

2. 合理缓存复用 RDD

被多个 Action 或多次 collect 使用的 RDD 应提前 cache(),避免重算。

3. 尽早过滤

在 transformation 链的尽可能早的阶段执行 filter(),减少后续算子处理的数据量。

4. 选择正确的聚合算子

// 低效:groupByKey 将所有 value 传输后再聚合,shuffle 数据量大
rdd.groupByKey().mapValues(_.sum)

// 高效:reduceByKey 在 Map 端预聚合,显著减少 shuffle 数据量
rdd.reduceByKey(_ + _)

5. 广播大变量

超过数 MB 的共享变量(字典表、模型参数)应使用广播变量,避免随每个 Task 重复传输。

提交参数参考

spark-submit \
  --master spark://master:7077 \
  --deploy-mode client \          # client: Driver 在本地; cluster: Driver 在集群
  --num-executors 4 \
  --executor-cores 2 \
  --executor-memory 4g \
  --driver-memory 2g \
  --class com.example.MyApp \
  myapp.jar