2026/8/6 15:25:29

Spark on YARN 部署模式与资源参数配置实战指南

Spark on YARN 部署模式与资源参数配置实战指南 最近在搞大数据项目团队里好几个同学都遇到了 Spark 作业提交到 YARN 集群后卡在ACCEPTED状态迟迟无法运行或者运行中频繁失败的问题。排查下来十有八九跟--master参数和资源分配有关。一句spark-submit --master yarn背后其实藏着从客户端到 ResourceManager再到 NodeManager 的一整套调度逻辑。参数配不对资源要不到作业就只能干等着。本文将彻底拆解 Spark on YARN 的--master参数配置从核心概念、两种部署模式client cluster的差异到资源请求--num-executors,--executor-memory等的详细配置策略最后给出一个从打包到提交、监控的完整实战案例。无论你是刚接触 Spark 的新手还是遇到过资源问题的开发者都能从中找到清晰的配置思路和避坑指南。1. Spark on YARN 核心概念与架构在独立部署Standalone模式下Spark 自带资源管理。但在企业级大数据平台中YARNYet Another Resource Negotiator通常是统一资源调度和管理的中枢。Spark on YARN 的本质是让 Spark 作为 YARN 框架上的一个应用Application来运行由 YARN 来负责分配和管理 Spark 作业所需的计算资源CPU、内存。1.1 核心角色映射理解 Spark on YARN首先要搞清楚 Spark 自身的角色如何映射到 YARN 的体系中Spark Driver 这是 Spark 应用的“大脑”负责解析用户代码、构建 DAG、生成执行计划、调度 Task。在 YARN 环境下Driver 可以运行在两种地方这也就是两种部署模式的由来。Spark Executor 这是执行具体 Task 的“工人”负责运行任务并将数据返回给 Driver。在 YARN 中每个 Executor 对应一个YARN Container。YARN ResourceManager (RM) 集群资源的“总管家”负责整个集群资源的统一管理和调度。YARN NodeManager (NM) 单个节点上的“监工”负责启动和管理本节点上的 Container并监控资源使用情况。1.2 两种部署模式Client vs Cluster--master yarn后面必须跟一个--deploy-mode参数来指定部署模式这是所有问题的起点。--deploy-mode client(客户端模式)Driver 位置 Driver 进程运行在提交作业的客户端机器上比如你的开发机或边缘节点。工作流程你在客户端执行spark-submit。Spark 直接在本地启动 Driver。Driver 向 YARN RM 申请资源Executor 的 Container。YARN NM 启动 Executor Container并与本地 Driver 建立连接。优点便于调试 Driver 在本地你可以直接看到stdout/stderr日志方便使用 debug 工具。交互式友好 Spark Shell (spark-shell, pyspark) 必须使用此模式。缺点客户端依赖 客户端必须与集群网络互通且客户端进程必须长期存活。如果客户端断开作业就失败了。资源占用 Driver 消耗客户端的资源。网络开销 Driver 与 Executor 可能跨网络通信有一定性能损耗。--deploy-mode cluster(集群模式)Driver 位置 Driver 进程运行在YARN集群的某个Container中通常由 ApplicationMaster 担任。工作流程你在客户端执行spark-submit。客户端将作业提交给 YARN RM 后任务就结束了。YARN RM 选择一个节点启动一个特殊的 Container 来运行ApplicationMaster (AM)。在 Spark 中这个 AM 就包含了 Driver。AM (Driver) 再向 RM 申请资源启动 Executor Container。优点生产环境首选 客户端提交后即可退出作业由集群全权管理更稳定。资源统一管理 Driver 的资源也由 YARN 管理更合理。更好的负载均衡 Driver 可能在离数据更近的节点启动。缺点日志查看不便 需要通过 YARN 命令或 Web UI 来查看 Driver 日志。调试稍复杂 不能直接 attach 到 Driver 进行交互式调试。模式选择建议开发、测试、交互式分析 使用client模式。生产环境作业 务必使用cluster模式。2. 环境准备与版本说明在开始配置和提交作业前请确保你的环境满足以下条件。版本差异可能导致参数不兼容或行为异常。2.1 基础环境要求操作系统 Linux如 CentOS 7 Ubuntu 18.04是生产环境标准。Mac/Win 可用于本地开发测试。Java 必须安装 JDK 8 或 JDK 11推荐 JDK 8。设置好JAVA_HOME环境变量。# 检查Java版本 java -version # 输出应类似 openjdk version 1.8.0_392Hadoop/YARN 集群 需要一个正常运行的 Hadoop 集群包含 HDFS 和 YARN。本文示例基于Hadoop 3.x。Spark 下载与 Hadoop 版本对应的 Spark Pre-built 包。例如为 Hadoop 3.2 下载spark-3.3.2-bin-hadoop3.tgz。解压并设置SPARK_HOME。export SPARK_HOME/opt/spark-3.3.2-bin-hadoop3 export PATH$SPARK_HOME/bin:$PATH2.2 关键配置检查Spark 需要知道 YARN 和 HDFS 的地址。主要配置在$SPARK_HOME/conf/spark-defaults.conf和$SPARK_HOME/conf/spark-env.sh中。确保HADOOP_CONF_DIR或YARN_CONF_DIR环境变量指向正确的配置目录该目录包含core-site.xml,hdfs-site.xml,yarn-site.xml。这是 Spark 与集群通信的基础。# 在 spark-env.sh 中设置或直接导出环境变量 export HADOOP_CONF_DIR/etc/hadoop/conf检查spark-defaults.conf中的基础配置可选部分参数可通过命令行传递# 示例配置 spark.master yarn spark.eventLog.enabled true spark.eventLog.dir hdfs://namenode:8020/spark-logs spark.history.fs.logDirectory hdfs://namenode:8020/spark-logs spark.serializer org.apache.spark.serializer.KryoSerializer2.3 客户端网络在client模式下提交作业的机器必须能与 YARN ResourceManager 和 HDFS NameNode 通信通常通过主机名或IP。在cluster模式下提交后客户端可断开但提交瞬间也需要连通 RM。3.spark-submit核心参数详解spark-submit是提交作业的入口其参数决定了作业的行为。我们来重点解析与--master和资源相关的核心参数。3.1 主参数--master和--deploy-mode这是作业的“总开关”。# 完整格式 spark-submit \ --master yarn \ --deploy-mode client|cluster \ ...--master yarn 指定资源管理器为 YARN。--deploy-mode cluster生产环境标配。如果不指定Spark 2.0 的默认模式是client但强烈建议显式指定。3.2 资源请求参数这些参数告诉 YARN 你需要多少资源。配置不合理是作业卡住或失败的最主要原因。--num-executorsExecutor 数量。这是并行的核心。设置太少无法利用集群资源设置太多会增加调度开销。一般建议从集群总核数的 1/3 到 1/2 开始估算。--executor-memory每个 Executor 的内存。格式如4g,8192m。这包括 Executor 中用于缓存、任务执行的内存。必须小于 YARN 单个 Container 的最大内存限制由yarn.scheduler.maximum-allocation-mb决定并预留一部分约10%给堆外内存和系统开销。--executor-cores或--executor-cores每个 Executor 使用的 CPU 核心数。决定了每个 Executor 内并行运行的 Task 数。通常设置为 3-5以避免 HDFS 客户端瓶颈和过高的并发开销。--driver-memoryDriver 进程的内存。在cluster模式下Driver 运行在 YARN Container 中此内存也受 YARN 限制。如果作业需要收集大量数据如collect()需要增加此值。--driver-coresDriver 进程的 CPU 核心数Spark 3.0 更常见。默认为1。一个经典的内存配置示例 假设 YARN 的 NM 配置了yarn.nodemanager.resource.memory-mb16g节点总可用内存yarn.scheduler.maximum-allocation-mb8g单个 Container 最大内存。 那么一个安全的 Executor 内存配置可以是--executor-memory 6g为堆外和系统留出 2g 空间。Driver 内存--driver-memory 2g通常足够。3.3 应用相关参数--class 你的 Spark 应用主类对于 Java/Scala。--name 应用名会在 YARN Web UI 和日志中显示便于识别。--jars 用逗号分隔的额外 Jar 包列表会被分发到 Driver 和 Executor 的 classpath。--files 用逗号分隔的文件列表如配置文件会被分发到每个工作节点可通过SparkFiles.get(filename)访问。--conf 设置任意的 Spark 配置属性格式为keyvalue。这是最灵活的配置方式可以覆盖spark-defaults.conf中的设置。4. 完整实战提交 WordCount 作业到 YARN让我们通过一个完整的 Scala 项目示例演示如何打包、配置并提交一个 Spark 作业到 YARN 集群运行。4.1 项目结构与代码假设我们有一个简单的 SBT 项目。wordcount-yarn-demo/ ├── build.sbt ├── src/ │ └── main/ │ └── scala/ │ └── com/ │ └── example/ │ └── WordCount.scala └── project/ └── build.propertiesbuild.sbtname : wordcount-yarn-demo version : 1.0 scalaVersion : 2.12.15 // 与你的Spark版本Scala兼容版本一致 libraryDependencies org.apache.spark %% spark-core % 3.3.2 % provided // 使用 provided 是因为集群环境中已有Spark Jarsrc/main/scala/com/example/WordCount.scalapackage com.example import org.apache.spark.sql.SparkSession object WordCount { def main(args: Array[String]): Unit { // 1. 创建SparkSession这是Spark 2.x的入口 val spark SparkSession.builder() .appName(WordCount on YARN) // 此处名称可被命令行--name覆盖 .getOrCreate() import spark.implicits._ val sc spark.sparkContext // 2. 读取命令行第一个参数作为输入路径第二个作为输出路径 val inputPath args(0) val outputPath args(1) // 3. 核心WordCount逻辑 val textFile sc.textFile(inputPath) val counts textFile .flatMap(line line.split( )) .map(word (word, 1)) .reduceByKey(_ _) // 4. 将结果保存到HDFS counts.saveAsTextFile(outputPath) // 5. 打印一些统计信息到Driver日志在cluster模式下需通过yarn logs查看 println(sTotal unique words: ${counts.count()}) // 也可以收集少量数据到Driver端谨慎使用数据量大时会OOM // counts.take(10).foreach(println) // 6. 停止SparkContext spark.stop() } }4.2 打包项目在项目根目录下使用 SBT 打包一个不含 Spark 依赖的“瘦”Jar因为依赖已由集群提供。cd wordcount-yarn-demo sbt package成功后在target/scala-2.12/目录下会生成wordcount-yarn-demo_2.12-1.0.jar。4.3 准备测试数据并上传至 HDFS# 本地创建一个测试文件 echo hello spark hello world test.txt echo goodbye spark hello yarn test.txt # 上传到HDFS hdfs dfs -mkdir -p /user/$USER/spark_input hdfs dfs -put test.txt /user/$USER/spark_input/ hdfs dfs -ls /user/$USER/spark_input4.4 使用 spark-submit 提交作业Cluster 模式这是最核心的一步。我们使用cluster模式并指定合理的资源。spark-submit \ --master yarn \ --deploy-mode cluster \ --name MyWordCountClusterJob \ --class com.example.WordCount \ --num-executors 2 \ --executor-memory 2g \ --executor-cores 2 \ --driver-memory 1g \ --conf spark.yarn.queuedefault \ --conf spark.serializerorg.apache.spark.serializer.KryoSerializer \ /path/to/your/wordcount-yarn-demo_2.12-1.0.jar \ hdfs://namenode-host:8020/user/$USER/spark_input/test.txt \ hdfs://namenode-host:8020/user/$USER/spark_output参数解释--master yarn --deploy-mode cluster 指定 YARN 集群模式。--num-executors 2 --executor-memory 2g --executor-cores 2 请求 2 个 Executor每个有 2G 内存和 2 个核心。--driver-memory 1g Driver 分配 1G 内存。--conf spark.yarn.queuedefault 指定 YARN 调度队列。最后一行是 Jar 包路径和两个程序参数输入路径和输出路径。请将namenode-host替换为你的 NameNode 主机名或 IP。4.5 监控作业与查看结果提交后命令行会打印出application_XXXX_YYYY格式的应用 ID 和跟踪 URL。Application report for application_1678888888888_0001 (state: ACCEPTED) ... Tracking URL: http://rm-host:8088/proxy/application_1678888888888_0001/通过 YARN Web UI 监控 打开浏览器访问http://rm-host:8088找到你的应用可以查看状态、资源使用、日志等。查看日志# 使用yarn logs命令在应用结束后也能查看 yarn logs -applicationId application_1678888888888_0001查看输出结果hdfs dfs -cat /user/$USER/spark_output/part-* # 预期输出类似 # (hello,3) # (spark,2) # (world,1) # (goodbye,1) # (yarn,1)4.6 Client 模式提交对比如果你只是想快速测试可以在能连通集群的客户端机器上使用client模式。此时Driver 日志会直接打印在终端。spark-submit \ --master yarn \ --deploy-mode client \ # 显式指定client模式 --name MyWordCountClientJob \ --class com.example.WordCount \ --num-executors 1 \ --executor-memory 1g \ /path/to/your/jarfile.jar \ hdfs://.../input \ hdfs://.../output # 作业运行时的stdout/stderr会直接输出到当前终端5. 常见问题与排查思路作业提交后最常遇到的就是ACCEPTED状态等待、FAILED状态或运行缓慢。下面是一个排查清单。问题现象可能原因排查步骤与解决方案应用一直处于 ACCEPTED 状态1.集群资源不足队列资源已满。2.资源请求超出限制executor-memory或executor-cores超过了 YARN 的maximum-allocation-mb或maximum-allocation-vcores。3.调度队列配置错误指定的队列不存在或无权限。1. 检查 YARN RM Web UI 的调度器页面看队列资源使用情况。2. 检查yarn-site.xml中的yarn.scheduler.maximum-allocation-mb和yarn.scheduler.maximum-allocation-vcores值并确保请求资源小于该值。3. 检查--conf spark.yarn.queue指定的队列名是否正确或尝试提交到default队列。应用 FAILED报错Container exited with a non-zero exit code 11.内存不足 (OOM)最常见。Executor 或 Driver 内存设置过小。2.类找不到 (ClassNotFoundException)依赖 Jar 包未正确分发。3.HDFS/Hive 等连接失败网络或配置问题。1.查看日志yarn logs -applicationId appId是第一步。重点看stderr。2.针对 OOM查看日志中是否有java.lang.OutOfMemoryError。适当增加--executor-memory或--driver-memory并检查代码中是否有collect()、take(n)n过大等操作。3.针对 ClassNotFound确保通过--jars指定了所有第三方依赖或使用spark-submit --packages从仓库下载。对于cluster模式确保 Jar 包路径是全局可访问的如 HDFS。应用运行极其缓慢1.数据倾斜某个 Task 处理的数据量远大于其他。2.Executor 资源分配不合理executor-cores过多导致 HDFS 客户端争用或num-executors太少。3.GC 时间过长内存不足或配置不当导致频繁 Full GC。1. 查看 Spark UI通过 YARN 的 Tracking URL 进入的 Stages 页面检查每个 Task 的执行时间是否差异巨大。2. 调整资源通常executor-cores设为 3-5executor-memory根据数据量调整保证足够的并行度 (num-executors * executor-cores)。3. 在 Spark UI 的 Executors 页签查看 GC 时间。可尝试调整 JVM GC 参数如--conf spark.executor.extraJavaOptions-XX:UseG1GC。client模式提交后客户端断开导致作业失败客户端进程终止如 SSH 断开Driver 随之终止。生产作业务必使用cluster模式。如果必须在client模式下运行长时作业可使用nohup或screen/tmux等工具保持会话。报错Service sparkDriver could not bind on port XXXXDriver 要绑定的端口被占用多见于client模式多任务并行提交时。设置随机端口或指定不同端口--conf spark.driver.port0随机或--conf spark.driver.port特定端口。6. 最佳实践与工程建议掌握了基础提交和排错后以下实践能让你的 Spark on YARN 作业更稳健、高效。6.1 资源调优黄金法则理解数据量 根据输入数据大小估算内存。一个粗略的经验是Executor 内存应能容纳该 Executor 要处理的数据分区。避免微小 Executor 不要启动大量内存很小如 1g的 Executor。每个 Executor 有固定的开销如堆外内存、线程。建议单个 Executor 内存至少4g-8g。留出系统开销 YARN 的yarn.nodemanager.resource.memory-mb是 NodeManager 可用的总内存。设置spark.executor.memory时要小于(总内存 / 容器数)并预留约10%-15%给堆外内存spark.yarn.executor.memoryOverhead和系统。核心数设置spark.executor.cores通常设为3-5。每个核心运行一个 Task。设置太多会导致 HDFS 客户端并发过高可能成为瓶颈。动态资源分配 对于批处理作业可以考虑启用动态资源分配让 Spark 根据负载自动调整 Executor 数量。--conf spark.dynamicAllocation.enabledtrue \ --conf spark.dynamicAllocation.minExecutors2 \ --conf spark.dynamicAllocation.maxExecutors20 \ --conf spark.dynamicAllocation.initialExecutors4 \ --conf spark.shuffle.service.enabledtrue # 需要YARN上启动Spark Shuffle Service6.2 配置管理优先使用--conf命令行参数 对于作业特定的配置如资源参数在spark-submit命令行中指定便于版本管理和参数化。使用spark-defaults.conf管理集群级默认配置 如序列化器、压缩编码、网络超时等通用设置。分离配置与代码 将输入输出路径、数据库连接等变量通过命令行参数或外部配置文件--files分发传递不要硬编码在代码中。6.3 日志与监控启用事件日志 在spark-defaults.conf中配置spark.eventLog相关设置将事件日志写到 HDFS。便于通过 Spark History Server 查看已结束作业的详细 UI。合理设置日志级别 在开发时可设为INFO生产环境可设为WARN以减少日志量。--conf spark.driver.extraJavaOptions-Dlog4j.configurationfile:/path/to/log4j.properties \ --conf spark.executor.extraJavaOptions-Dlog4j.configurationfile:/path/to/log4j.properties熟悉监控指标 通过 Spark UI 关注Storage Memory、GC Time、Shuffle Spill、Scheduler Delay等关键指标它们是性能调优的重要依据。6.4 安全与稳定性队列与权限 在多租户集群中使用--queue指定正确的队列并了解该队列的资源容量和优先级。处理数据倾斜 在代码中使用repartition、salting等技术避免数据倾斜这是导致作业慢或 OOM 的元凶之一。优雅关闭 对于流处理作业考虑设置spark.yarn.maxAppAttempts最大重试次数和spark.yarn.am.attemptFailuresValidityInterval失败窗口并处理好 checkpoint确保应用能从故障中恢复。资源隔离 考虑使用 YARN 的标签调度或 Docker 容器化为不同的 Spark 作业或租户提供更好的资源隔离。从一句简单的spark-submit --master yarn开始到根据业务数据量和集群状况精细调配--num-executors、--executor-memory、--executor-cores等参数是每个 Spark 开发者从入门到精通的必经之路。记住在cluster模式下你的应用在 YARN 的管理下会变得更加健壮而善用 Spark UI 和 YARN 日志则是你排查问题、优化性能最有力的工具。刚开始可以基于文中的示例配置进行尝试然后结合自己作业的实际情况观察监控指标逐步调整最终找到最适合自己业务场景的资源配方。