news 2026/10/10 14:50:25

Spark on YARN从零配置实战:版本选型、内存参数与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spark on YARN从零配置实战:版本选型、内存参数与避坑指南

去年接了一个数据平台的活,团队里几个新同学上来就被 Spark 配置折腾得够呛。明明看文档都会,一上集群就各种ClassNotFoundException、Container exited、物理内存超限。我自己的经验是,Spark 的配置说难不难,但它藏在一堆配置文件、版本兼容性和资源参数里,不把整张地图画出来,你永远都在碰运气。这篇东西我就按从零到 YARN 的顺序,把 Spark 配置这件事彻底拆开。

这篇指南适合三种人:刚接触 Spark 想在本机跑通第一个程序的新手,准备搭测试集群却被版本和路径问题卡住的同学,以及生产环境想从 Standalone 平滑迁移到 YARN 的开发者。整个配置过程我会按实际动手的顺序来讲,每个文件该写什么、为什么这么写、踩过哪些坑,都会交代清楚,你可以直接照着抄。

1. 动手前的准备:环境与版本一次说清

很多教程上来就让你下载 Spark,结果你按着老版本博客配完,跑任务时报一堆错,只能干瞪眼。我先把底层的环境问题说透。

1.1 服务器与依赖清单

Spark 是跑在 JVM 上的,所以第一件事是装 JDK。这里有个关键点:Spark 3.x 要求 Java 8 或 Java 11,Spark 4.x 之后主流推荐 Java 17。很多老博客还停留在 Java 8,你要是用 17 去跑老版本 Spark,大概率直接启动失败。

我在生产环境常用的组合是:

  • 操作系统:CentOS 7.9 或 Ubuntu 20.04/22.04 LTS,两者没有本质区别,只是安装依赖包的命令不同
  • JDK:OpenJDK 1.8 或 11
  • Hadoop:3.2.x 或 3.3.x,主要用于 YARN 和 HDFS
  • Spark:3.3.x 或 3.4.x

还有一个容易忽略的依赖是tar、wget、ssh,这些工具在搭建集群时缺一不可。用java -version确认 JDK 装好,再用which ssh确认 ssh 可用,这比啥都重要。

1.2 版本选型:几个关键对应关系

版本选型是配置里最容易踩坑的地方,我直接给你一张我实测过的对应表。

Spark 版本JDK 要求Scala 版本Hadoop/YARN 兼容建议
Spark 3.2.x8 / 112.12Hadoop 3.2+
Spark 3.3.x8 / 11 / 172.12Hadoop 3.3+
Spark 3.4.x8 / 11 / 172.12Hadoop 3.3+
Spark 4.0.x17 / 212.13Hadoop 3.3+

注意一个反直觉的点:Spark 官网编译好的二进制包,默认是针对 Hadoop 3 的版本。你去 Apache 下载页能看到spark-3.3.4-bin-hadoop3.tgz,这个就是最省事的包。以前还有without-hadoop版本,那个要求你自己带上 Hadoop classpath,新手别碰。

选版本时记住一句口诀:先定 Spark,再定 Hadoop,最后定 JDK。这句话的意思是,你的 Spark 版本决定了它能不能跑在某个 Hadoop 版本之上,而 JDK 版本既受 Spark 支持范围限制,又受 Hadoop 支持范围限制。我遇到过最典型的例子是有人用 Hadoop 2.7 配 Spark 3.3,编译时能过,运行时 YARN 的容器调度直接不认,白折腾了两天。

1.3 目录规划与软链接

配置环境的第一个隐性成本是目录混乱。我习惯统一规划:

/opt/jdk # JDK 安装目录 /opt/hadoop # Hadoop 安装目录 /opt/spark # Spark 安装目录 /data/hdfs # HDFS 数据目录 /data/yarn # YARN 本地目录与日志目录 /data/spark-logs # Spark 历史日志

用/opt而不是/usr/local的原因很简单:/opt给第三方软件包用,目录结构清晰,升级时直接替换整个目录不影响系统自带程序。多节点集群里,各机器目录保持一致,能少掉一半排查问题的时间。

2. 先把本地模式跑通

不管你想不想用 YARN,我强烈建议先把本地模式跑通。本地模式下 Spark 不需要集群,单机就能跑,它的作用是让你确认环境没问题、依赖没问题、代码逻辑没问题,之后再上 YARN 时定位问题就纯粹是资源问题了。

2.1 下载与解压

下载时我建议直接用 Apache 官方镜像:

wget https://dlcdn.apache.org/spark/spark-3.3.4/spark-3.3.4-bin-hadoop3.tgz tar -zxvf spark-3.3.4-bin-hadoop3.tgz -C /opt ln -s /opt/spark-3.3.4-bin-hadoop3 /opt/spark

用软链接ln -s是个好习惯。因为 Spark 升级时,你只需要把软链接指向新版本,所有环境变量不用改,服务重启即可。这个习惯帮我省了大量升级时间。

2.2 环境变量配置

编辑/etc/profile.d/spark.sh:

export SPARK_HOME=/opt/spark export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin export HADOOP_HOME=/opt/hadoop export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export YARN_CONF_DIR=$HADOOP_CONF_DIR

HADOOP_CONF_DIR和YARN_CONF_DIR这两个变量,在你后面接 YARN 时是必须的。Spark 启动时会自动读取这两个目录下的core-site.xml、hdfs-site.xml、yarn-site.xml,不需要你手动写 HDFS 地址。

配好之后用echo $SPARK_HOME验证,然后spark-shell --version看版本信息,能打印出版本就说明基础环境 OK。

2.3 用 spark-shell 验证

启动本机交互式环境:

spark-shell --master local[2]

看到Spark context Web UI available at http://localhost:4040就说明起来了。然后跑一个最简单的任务:

val df = spark.range(1000).filter(_ % 2 == 0).count()

返回500就没问题。这一步实际验证了三件事:JVM 能启动、Spark 能读取依赖、任务调度能跑通。如果这一步有问题,你上 YARN 基本是浪费时间。

2.4 本地模式能干到什么程度

本地模式本质上是一个进程内模拟的分布式环境,local[2]是启用 2 个线程来模拟 2 个 executor。它能跑通大部分开发测试,但有两个明显问题:

  • 没有 HDFS,你的数据要么在本地磁盘,要么自己指定file://路径
  • 没有真正的资源隔离,一个任务内存超了直接拖垮整个 JVM

所以我的建议是:本地模式只用来验证逻辑,真正的集群行为必须上 YARN 验证,特别是内存和并行度相关的问题,本地模式完全模拟不出来。

3. 集群模式下的一些基础架设

在配置 YARN 之前,你得先有 YARN。这一节我不会把 Hadoop 的安装全部展开,但会把和 Spark 衔接最关键的部分讲清楚。

3.1 节点规划建议

一个最小可用的测试集群至少三台机器:

node01 NameNode + ResourceManager node02 DataNode + NodeManager node03 DataNode + NodeManager

生产环境里 ResourceManager 和 NameNode 通常分开部署,但测试环境合在一起没毛病。NodeManager 是真正运行 Spark Executor 的地方,所以它的内存和 CPU 直接决定你能跑多大的任务。

3.2 YARN 的几个核心配置

在 Hadoop 的yarn-site.xml里,这几个参数是 Spark 接入时必须对齐的:

<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>16384</value> </property> <property> <name>yarn.nodemanager.resource.cpu-vcores</name> <value>8</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>512</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>16384</value> </property>

yarn.nodemanager.resource.memory-mb表示每台机器能分给 YARN 的总内存。注意,这个值不是物理内存总量,而是 YARN 可以拿去跑容器的上限,一般留 2 到 4GB 给操作系统和系统进程。minimum-allocation-mb和maximum-allocation-mb决定了单个容器能申请的内存范围,Spark 的 executor 内存必须落在这个区间内,不然要么分配失败,要么被强制压制。

3.3 验证 YARN 本身是好的

在配 Spark 之前,先用 Hadoop 自带示例验证 YARN 能正常工作:

hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.4.jar pi 2 1000

如果能跑通并输出一个近似圆周率的值,说明 YARN 调度正常、NodeManager 心跳正常、HDFS 可用。这一步能把你之后的问题范围从"环境坏没坏"缩小到"Spark 配置对不对"。

4. 核心章节:接入 YARN 的完整配置

到这里,前置条件都就位了,开始真正配置 Spark 的 YARN 模式。

4.1 为什么要切到 YARN

很多人会问,Spark 不是自带集群模式吗?为什么非要用 YARN?我的理解是:YARN 是 Hadoop 生态的统一资源调度层,它不只管 Spark,还管 MapReduce、Flink 等计算框架。生产环境里你的集群不可能只跑 Spark,YARN 能让所有计算框架共享同一批机器资源,而且能做到队列隔离和公平调度。

另外还有一个现实原因:你要读 HDFS 上的数据,就绕不开 YARN 的运行环境。虽然 Spark 可以直接读 HDFS,但 YARN 模式能让 Spark 应用以容器方式运行在 NodeManager 上,资源超了由 YARN 直接杀掉,不会拖垮整个节点。

4.2 核心配置文件逐项说明

Spark 接入 YARN 需要改两个文件:spark-env.sh和spark-defaults.conf。

spark-env.sh主要配置运行时环境:

export JAVA_HOME=/opt/jdk export HADOOP_HOME=/opt/hadoop export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export SPARK_HOME=/opt/spark export SPARK_LOG_DIR=/data/spark-logs

这里我特意写JAVA_HOME而不是直接写java,因为有些机器的默认 Java 是系统自带的 OpenJDK,版本不对。显式指定后,Spark 启动脚本会用你指定的 JDK,避免系统更新把默认 Java 版本换掉后 Spark 突然起不来。

spark-defaults.conf是另一个重头文件:

spark.master yarn spark.eventLog.enabled true spark.eventLog.dir hdfs://node01:8020/spark-logs spark.history.fs.logDirectory hdfs://node01:8020/spark-logs spark.yarn.archive hdfs://node01:8020/spark-libs/spark-archive.zip spark.driver.memory 2g spark.executor.memory 4g spark.executor.cores 2 spark.sql.shuffle.partitions 16

spark.master设为yarn之后,Spark 的脚本会调用 YARN 的 ResourceManager 提交应用。spark.yarn.archive这个参数容易被忽略,它的作用是把 Spark 的依赖 jar 打包放到 HDFS 上,这样每个 executor 启动时从 HDFS 拉依赖,速度远快于从本地磁盘逐台分发。部署时执行:

cd $SPARK_HOME/jars zip -r spark-archive.zip . hdfs dfs -mkdir -p /spark-libs hdfs dfs -put spark-archive.zip /spark-libs/

spark.eventLog.enabled和spark.history.fs.logDirectory配合使用,可以在 Spark History Server 上回看应用的事件日志,排查问题时特别有用。

4.3 资源参数:executor 内存与 core 怎么定

这是配置 YARN 模式的核心知识点。Spark 在 YARN 上会向 ResourceManager 申请两种资源:内存和 CPU。每个 executor 向 YARN 申请的总内存是:

总内存 = spark.executor.memory + spark.executor.memoryOverhead

spark.executor.memory是堆内内存,主要给 RDD、DataFrame、Shuffle 数据用。memoryOverhead是堆外内存,默认是 executor.memory 的 10%,还设有下限 384MB,给 JVM 的 Metaspace、线程栈、网络缓冲等用。我在生产环境常用的经验参数是:

spark.executor.memory 4g spark.executor.memoryOverhead 1g spark.executor.cores 2

这里最关键的检查点是:executor 总内存加 driver 内存,不能超过 NodeManager 可用资源。比如 NodeManager 有 16GB 内存、8 核,你有 3 台机器,那么并发起来最多同时跑的容器数大概是:

单节点容器数 = 16GB / (4GB + 1GB) ≈ 3

如果你强行把 executor.memory 设成 8GB,单个容器 8GB 加 overhead 900MB,YARN 可能因为超过maximum-allocation-mb直接拒绝分配,任务卡在 ACCEPTED 状态不动。这是新手最常遇到的事。

4.4 在 YARN 上跑第一个任务

配置完成后,用官方示例验证:

$SPARK_HOME/bin/spark-submit \ --master yarn \ --deploy-mode cluster \ --class org.apache.spark.examples.SparkPi \ $SPARK_HOME/examples/jars/spark-examples_2.12-3.3.4.jar

跑通后访问 ResourceManager 的 Web 界面(默认 8088 端口),可以看到一个SparkPi的应用状态从 ACCEPTED 变成 RUNNING,最后 FINISHED。再去 YARN 日志或者 Spark History Server 里看 stdout,能找到计算结果。

我习惯再跑一个读 HDFS 文件的 WordCount 来做更真实的验证:

val rdd = sc.textFile("hdfs://node01:8020/data/input.txt") rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _).saveAsTextFile("hdfs://node01:8020/data/output")

这次验证覆盖了数据源、Shuffle、结果输出,只要你这三个环节都通,Spark 在 YARN 上的链路就算彻底打通了。

5. 内存配置再深挖

很多 Spark 任务跑挂了,九成跟内存有关。这一节我重点把内存配置背后的逻辑说透,而不是只让你抄参数。

5.1 Spark 内存模型快速梳理

Spark 3.0 之后启用了统一内存管理。一个 executor 的堆内内存分三块:

  • Storage 区域:存 RDD 缓存和 Broadcast 数据
  • Execution 区域:存 Shuffle、聚合、Join 产生的临时数据
  • Reserved 区域:为系统预留

两类区域之间可以互相借用,Storage 空闲时 Execution 可以借过去,反之亦然。这就是"统一内存"的含义。所以在配置上,spark.memory.fraction默认 0.6,表示堆内内存 60% 分配给 Storage 和 Execution 共同使用,其余留给用户代码生成的临时对象。

5.2 常见内存配置参数对照

参数默认值作用我常用的调整方向
spark.executor.memory1g堆内内存上限根据数据量调大,2g 起步
spark.executor.memoryOverhead10%堆外内存大 Shuffle 时手动提高到 1g
spark.driver.memory1gDriver 端堆内内存有collect操作时调到 2g 以上
spark.memory.fraction0.6Storage+Execution 占比纯 Shuffle 任务可调到 0.7
spark.shuffle.file.buffer32kShuffle 写缓冲大 Shuffle 时调到 128k

一个容易忽略的点:spark.driver.memory。当你用collect把数据拉回 Driver,或者 Driver 要广播大字典时,默认 1g 远远不够。我见过一个任务把几十万行结果collect回 Driver,直接 OOM 把 YARN 上的 AM 容器干掉了,重启循环直到失败。

5.3 数据倾斜与内存问题的实战关联

很多内存异常根因是数据倾斜,而不是配置参数本身。数据倾斜最简单的表现是:整个任务卡在某个 stage 的 99%,日志里大量GC overhead limit exceeded。

我的排查思路是:先用 Web UI 看 Shuffle Read Size 是否严重不均,然后看单个 executor 的 GC 时间是否异常长。定位后优先通过加盐两阶段聚合、调整分区数解决,而不是一味调大内存。盲目把 executor.memory 从 4g 调到 8g,YARN 可能就直接没资源可用了。

6. 常见问题与排查技巧实录

最后这部分是我踩坑最多的地方,我整理成速查表,再讲几个典型的排查思路。

6.1 问题速查表

症状常见原因快速检查方法解决方案
Application ACCEPTED 后一直不启动资源不足,等待调度看 YARN UI 的 Pending降低 executor 内存或增加队列资源
Container exited with code 143executor 被 YARN 强杀(内存超限)看 NodeManager 日志调大 memoryOverhead
ClassNotFoundException: org.apache.spark.*Spark 依赖未传到 executor检查 spark.yarn.archive执行 archive 打包上传
Spark 起不来,Java 版本报错JDK 不兼容java -version对照 Spark 要求到 spark-env.sh 指定 JAVA_HOME
读 HDFS 报FileNotFoundExceptionHDFS 地址写错确认hdfs-site.xml中的 NameNode 地址用hdfs dfs -ls测试
日志显示No space left on device本地临时目录满了df -h看 /data 分区配spark.local.dir到多块盘

6.2 一套靠谱的日志排查顺序

我的固定排查套路是自下而上看日志,先容器后框架:

  1. 先看 YARN ResourceManager 日志,确认应用是否被接收、被调度到哪个队列
  2. 再看 NodeManager 日志,确认容器启动失败的具体异常
  3. 然后看 Spark 应用的stderr和stdout,这通常浓缩了真正的 JVM 异常
  4. 最后看 Spark History Server 里的事件日志,按 stage 定位失败点

很多人一上来就grep Exception,结果 Log 里一堆 Footer 异常,浪费时间。顺序不对,容易被假象带跑。

6.3 几条独家避坑心得

第一,统一各节点的时间。YARN 对容器启动有时间判断,如果 NodeManager 和 ResourceManager 之间时间偏差大,会出现容器被判定为超时莫名杀掉。集群里装个 NTP 同步服务,是最省心的操作。

第二,spark.local.dir 一定要配。默认情况下 Spark 用/tmp作为本地临时目录,而/tmp在部分系统里容量很小,Shuffle 数据一多直接写满。配到独立数据盘:

spark.local.dir /data/spark-tmp,/data2/spark-tmp

多个目录用逗号分隔,Spark 会把临时文件分摊到不同磁盘,IO 压力也分散了。

第三,生产环境别轻易改 spark.sql.shuffle.partitions。默认 200 对大部分场景是合理的,不会太多也不会太少。我见过有人为了调性能改成 10,结果每个 task 的数据量暴增,Executor 直接 OOM。这个参数要结合文件大小、executor 数量来算,而不是拍脑袋。大概的参考是让每个 Shuffle 分片控制在 100MB 左右,用总 Shuffle 数据量除以 100MB 得到分区数。

第四,测试完记得关掉 Spark Shell。这个听起来像废话,但我见过开发环境里一堆僵尸 spark-shell 挂着,把 YARN

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 14:48:31

PyTorch CNN实战:MNIST手写数字识别课设包完整解析

简介&#xff1a;这份资源面向深度学习入门者与课程设计需求的学生&#xff0c;围绕卷积神经网络识别MNIST手写数字这一经典实验展开&#xff0c;帮助读者理解CNN的基本结构与训练流程。压缩包共11个文件&#xff0c;约176KB&#xff0c;包含Python脚本、Word设计报告、Markdow…

作者头像 李华
网站建设 2026/10/10 14:48:31

VOC手机检测数据集从零构建:标注、转换与踩坑指南

简介&#xff1a;面向目标检测算法训练与验证的数据集资源&#xff0c;围绕手机目标识别场景构建&#xff0c;适合使用YOLO、Faster-RCNN等主流框架的算法工程师、科研人员及计算机视觉学习者。包内共一万五千余个文件&#xff0c;包含五千余张真实场景jpg图片&#xff0c;以及…

作者头像 李华
网站建设 2026/10/10 14:46:03

LivePortrait 本地部署实战:ONNX 导出与 onnxruntime C++/Python 推理

简介&#xff1a;本资源面向希望在人像动画生成方向落地的开发者与算法工程师&#xff0c;提供一套基于onnxruntime推理的LivePortrait部署程序&#xff0c;同时给出C与Python两套实现&#xff0c;便于在桌面端或工程环境中集成。压缩包共14个文件&#xff0c;约459KB&#xff…

作者头像 李华
网站建设 2026/10/10 14:45:21

给AI编程助手补上长期记忆:claude-mem本地记忆工具实战指南

最近我在调整 AI 辅助编程的工作流时&#xff0c;踩了一个特别真实的坑&#xff1a;模型的单次对话能力再强&#xff0c;它依然不记得你昨天做过什么。上午我花了二十分钟跟命令行里的编程助手解释某个服务的调用约定&#xff0c;下午换了个文件继续写代码&#xff0c;它又把同…

作者头像 李华
网站建设 2026/10/10 14:44:47

SD卡参数错误不慌:镜像备份与数据恢复全流程

被“参数错误”吓到过的人应该不少。插上SD卡准备导照片&#xff0c;双击盘符&#xff0c;屏幕上弹出一句“无法访问&#xff0c;参数错误”&#xff0c;那一刻多数人的第一反应就是&#xff1a;完了&#xff0c;几年照片全没了。但如果你真的因此把卡格式化或者直接扔进抽屉吃…

作者头像 李华