
1. 项目概述为什么非得把 Spark 塞进 YARN 里跑“Spark on YARN”这六个字不是一句技术口号而是过去十年大数据平台演进中一个被反复验证、踩过无数坑后沉淀下来的务实选择。我最早在某高校实验室搭第一套离线分析平台时用的是纯 Standalone 模式——三台机器手动配 master/slave写个spark-submit --master spark://xxx:7077就能跑起来看着 Web UI 上那几条任务线跳动还挺有成就感。但当数据量从 GB 级涨到 TB 级业务方开始提“明天要加个实时用户行为漏斗”运维同事又同步反馈“HDFS 已经占满 85%YARN 队列空闲率却常年 60%”时我才真正意识到资源割裂才是压垮集群的第一块石头。Spark on YARN 的本质不是换个启动方式那么简单它是把 Spark 这个“计算引擎”主动交出资源调度权嵌入到 YARN 这个“集群操作系统”里。YARN 不再只是 Hadoop MapReduce 的专属管家它成了整个集群的通用资源协调中枢——内存、CPU、磁盘 IO、网络带宽全由 ResourceManager 统一分配、公平调度、按需伸缩。你提交一个 Spark 作业YARN 动态给你拉起 ApplicationMasterAMAM 再向 NodeManager 申请 Container 启动 Executor而同一时刻Hive 的 Tez 任务、Flink 的流处理 Job、甚至一个 Python 脚本调用的 SparkR 分析都在共享同一套资源池。这种“一脑多用”的能力直接让集群资源利用率从 30% 提升到 65%~75%运维不再需要为每个框架单独划机器、配参数、盯 GC 日志。标题里提到的“圆周率案例”和“WordCount 案例”绝不是为了凑数的教学玩具。它们是 Spark on YARN 的“双面验钞机”圆周率Pi Estimation是典型的 CPU 密集型、无外部依赖、纯计算逻辑的“裸金属压力测试”。它不读 HDFS不连 Hive只靠随机数生成和聚合能最干净地暴露 YARN 资源分配是否均匀、Executor 启动是否延迟、Shuffle Manager 在 Container 间通信是否稳定。我见过太多集群跑 WordCount 没问题一跑 Pi 就卡在Waiting for AM container最后发现是 NodeManager 的yarn.nodemanager.resource.memory-mb配得太小连 AM 自己都抢不到内存。WordCount则是 I/O 密集型 网络 Shuffle 的“全流程体检”。它必须读取 HDFS 上的真实文件比如/data/input/下的文本触发 Block Location 获取、DataNode 本地性优化、Map 端 Combiner、Shuffle Write/Read、Reduce 端聚合……每一步都牵扯 YARN 的资源隔离策略、HDFS 客户端配置、网络拓扑感知能力。一次失败的 WordCount 提交往往能精准定位出core-site.xml里fs.defaultFS指向错误、yarn-site.xml中yarn.resourcemanager.hostname解析超时、或者spark-defaults.conf里spark.yarn.archive指向的依赖包路径权限不对等底层问题。所以这不是“学个命令怎么敲”的问题而是理解“谁在管资源、谁在管计算、谁在管数据、三者如何握手”的系统级认知重构。接下来我会带你从零开始像部署一个真实生产服务那样把 Spark 真正“种”进 YARN 的土壤里而不是浮在表面跑两个 demo。所有配置项、参数值、报错日志、排查路径都来自我亲手调试过的 7 个不同版本集群CDH 6.3.2 / HDP 3.1.4 / Apache Hadoop 3.2.1 Spark 3.1.2没有一行是抄文档的。2. 核心设计思路为什么是 YARN而不是 Mesos 或 Kubernetes在动手之前必须直面一个常被忽略的问题为什么是 YARN现在 Kubernetes 如日中天Flink 官方主推 Native K8s连 Spark 3.0 也加了 K8s 支持。但如果你正在维护一套已有的 Hadoop 生态HDFS Hive HBase或者你的团队对 YARN 的运维经验远多于 K8s那么强行切 K8s 不是升级是重构。我参与过两个迁移项目一个成功一个回滚。成功的那个是新起一套 K8s 专跑实时 FlinkYARN 专注离线 Spark回滚的那个是试图把所有历史 Spark 作业一键迁到 K8s结果发现旧版 Hive Metastore 的 Thrift Server 在 K8s Service Mesh 下连接超时临时改配置又引发 Kerberos 认证链断裂——两周没跑通一个 WordCount。YARN 的不可替代性在于它与 Hadoop 生态的“基因耦合”2.1 资源模型的深度绑定YARN 的核心抽象是Container—— 一个被严格限制内存MB、虚拟核数vCores的进程沙盒。Spark 的 Executor本质上就是一个运行在 Container 里的 JVM 进程。YARN 的yarn.scheduler.capacity.root.default.maximum-capacity控制队列最大资源占比yarn.nodemanager.resource.memory-mb定义单节点总内存上限这些参数直接映射到 Spark 的--executor-memory和--total-executor-cores。而 Kubernetes 的 Pod 资源是声明式的resources.requests.memory其底层 cgroup 限制粒度更粗且缺乏 YARN 那种细粒度的队列权重Capacity Scheduler或公平性Fair Scheduler保障。某次我们压测时K8s 集群上多个 Spark Job 并发一个大 Job 把所有节点内存打满其他 Job 直接 OOMKill而 YARN 队列能稳稳把资源按权重切分保底 20% 给高优队列。2.2 安全体系的无缝继承企业级 Hadoop 集群几乎 100% 启用 Kerberos 认证。YARN 的 ResourceManager 和 NodeManager 天然支持 Kerberos SPNEGOSpark on YARN 只需在客户端配置spark.yarn.principal和spark.yarn.keytab就能自动完成 AM 和 Executor 的票据续期renewal。而 K8s 原生不支持 Kerberos需额外部署 Key Distribution CenterKDCSidecar或改用 LDAP/AD 集成安全链路变长故障点增多。我亲眼见过一个金融客户因 K8s 的 KDC Sidecar 每 24 小时需手动重启续票导致凌晨批量 Spark 任务集体认证失败回滚到 YARN 后用kinit -R配合 cron 自动续期问题消失。2.3 数据本地性的硬性保障这是最容易被低估的一点。YARN 的 NodeManager 启动时会向 ResourceManager 上报本机的Rack ID和Host IP。当 Spark 的 ApplicationMaster 向 RM 申请 Container 时可以指定ResourceRequest的 locality机架本地、主机本地、任意。Spark 的 DAGScheduler 在划分 Stage 时会根据 HDFS 文件的 Block Location同样包含 Rack/Host 信息优先请求“同机架”甚至“同主机”的 Container 来运行 Map Task。这意味着90% 的数据读取走的是本地磁盘或同机架网络而非跨机房千兆网。而 K8s 的 Pod 调度器kube-scheduler默认不感知 HDFS 的 Rack 拓扑除非你手动给 Node 打 label如topology.kubernetes.io/rackrack1并写复杂的亲和性规则但 HDFS Client 本身并不解析这些 label数据本地性依然无法保证。某电商客户做商品推荐训练从 HDFS 读取 5TB 用户行为日志YARN 模式下 Shuffle Read 95% 为 LOCALK8s 模式下仅 40%网络成为瓶颈训练时间翻倍。因此本项目的架构选型不是“技术先进性”投票而是“风险可控性”决策目标集群已存在 HDFS YARN→ 优先复用降低学习成本与运维复杂度作业以离线批处理为主T1→ YARN 的吞吐量和稳定性优于 K8s 的弹性伸缩安全合规要求强审计日志、权限分级→ YARN 的 ACL 和 Kerberos 集成更成熟团队熟悉 Hadoop 生态工具链Ambari/Cloudera Manager→ 避免引入新运维界面。提示如果你的场景是“全新建设、无历史包袱、追求极致弹性”K8s 确实是未来方向。但本项目标题明确指向 YARN我们就扎根于此把它的能力榨干。3. 环境准备与核心配置从零搭建可运行的 Spark on YARN别急着敲spark-submit。在 YARN 上跑 Spark不是“装好就完事”而是“配准才起步”。我见过太多人卡在第一步Application failed 2 times due to AM Container for appattempt_... exited with exitCode: -1000。这个 -1000 错误码90% 是环境配置没对齐。下面是我整理的、经过 7 个集群验证的最小可行配置清单每一项都附带“为什么必须这样配”和“不配的后果”。3.1 基础环境一致性检查避坑第一关Spark on YARN 的核心前提是“客户端、YARN 服务端、HDFS 服务端”三方协议一致。这不是玄学是 Java 类加载机制决定的。检查项正确做法错误示范后果Java 版本所有节点Client/NN/DN/RM/NM统一使用JDK 8u2XX 或 JDK 11.0.1XSpark 3.1 推荐 JDK 11Client 用 JDK 11RM 用 JDK 8java.lang.NoSuchMethodError如Objects.requireNonNull在 JDK 8 不存在AM 启动失败日志里满屏ClassNotFoundExceptionHadoop 版本兼容性Spark 3.1.2 必须搭配Hadoop 3.2.x 或 3.3.x官方二进制包已内置对应 hadoop-client jar下载 Spark 官方without-hadoop包手动塞入 Hadoop 2.7.x 的 jarorg.apache.hadoop.fs.FileSystem类冲突No FileSystem for scheme: hdfs错误WordCount 读不了 HDFS主机名解析/etc/hosts中所有节点的 hostname 必须能互相 ping 通且hostname -f返回的 FQDN 与core-site.xml中fs.defaultFS的 host 部分完全一致hostname显示node1/etc/hosts写127.0.0.1 node1但core-site.xml里hdfs://namenode:9000YARN RM 无法注册 NMyarn node -list看不到节点Spark 提交后卡在Connecting to AM注意hostname -f的输出必须是完整的域名如node1.cluster.local不能是localhost或127.0.0.1。这是 Kerberos 认证的硬性要求即使你没开 KerberosYARN 内部通信也依赖此。3.2 YARN 关键参数配置yarn-site.xml这些参数决定了 Spark 应用能否“活下来”。我把它分成“生存底线”和“性能优化”两类生存底线必配否则 AM 启动即死!-- AM 自身的资源需求必须大于等于 Spark 默认值 -- property nameyarn.scheduler.minimum-allocation-mb/name value1024/value !-- 单个 Container 最小内存AM 至少要 1024MB -- /property property nameyarn.scheduler.maximum-allocation-mb/name value8192/value !-- 单个 Container 最大内存需 Spark executor-memory -- /property property nameyarn.nodemanager.resource.memory-mb/name value16384/value !-- 单节点总内存建议设为物理内存的 75% -- /property property nameyarn.nodemanager.resource.cpu-vcores/name value8/value !-- 单节点总 vCores建议设为物理 CPU 核数 -- /property !-- 关键AM 必须能访问 HDFS -- property nameyarn.application.classpath/name value$HADOOP_CONF_DIR,$HADOOP_COMMON_HOME/share/hadoop/common/*,$HADOOP_COMMON_HOME/share/hadoop/common/lib/*,$HADOOP_HDFS_HOME/share/hadoop/hdfs/*,$HADOOP_HDFS_HOME/share/hadoop/hdfs/lib/*,$HADOOP_YARN_HOME/share/hadoop/yarn/*,$HADOOP_YARN_HOME/share/hadoop/yarn/lib/*/value /property性能优化强烈建议提升稳定性!-- 启用容器日志聚合避免 NM 磁盘爆满 -- property nameyarn.log-aggregation-enable/name valuetrue/value /property !-- 日志保留 3 天足够排查问题 -- property nameyarn.log-aggregation.retain-seconds/name value259200/value /property !-- 关键启用分布式缓存让 Spark 的 jar 包能高效分发到所有 NM -- property nameyarn.nodemanager.remote-app-log-dir/name value/app-logs/value /property实操心得yarn.application.classpath是血泪教训。早期版本 Spark 需要手动把$HADOOP_HOME/etc/hadoop加入 classpath否则 AM 启动时找不到core-site.xml报java.net.UnknownHostException: namenode。现在官方包已内置但如果你用自定义编译的 Spark务必确认此项。3.3 Spark 客户端关键配置spark-defaults.confSpark 客户端即你敲spark-submit的机器的配置决定了它“怎么跟 YARN 说话”。参数推荐值为什么这么设不设的后果spark.masteryarn显式声明运行模式避免误用 local 模式默认是local[*]spark-submit会起本地线程根本连不上 YARNspark.submit.deployModeclient开发调试或cluster生产client模式 Driver 运行在提交机器日志实时可见cluster模式 Driver 运行在 AM 内适合生产免运维client模式下若提交机内存不足Driver OOMcluster模式下 Driver 日志需通过yarn logs -applicationId查看spark.yarn.jarshdfs://namenode:9000/spark-jars/*将 Spark 的所有依赖 jar 上传到 HDFS由 YARN 统一分发避免每个 NM 本地都要有完整 Spark 安装包不设则用--jars每次提交都传慢且易丢包或用spark.yarn.archive指向本地 zip但 NM 无法解压spark.executor.memory4g单 Executor结合yarn.nodemanager.resource.memory-mb16384一台 8 核机器可跑 3~4 个 Executor设太大如8g单节点只能跑 2 个 Executor资源碎片化设太小1gGC 频繁Shuffle 失败率高spark.executor.cores2一个 Executor 占 2 个 vCore匹配yarn.nodemanager.resource.cpu-vcores8单节点跑 4 个 Executor设为1Executor 过多AM 调度开销大设为4单节点仅 2 个 ExecutorCPU 利用率低提示spark.yarn.jars的 HDFS 路径必须存在且可读。执行hdfs dfs -mkdir -p /spark-jars然后hdfs dfs -put $SPARK_HOME/jars/*.jar /spark-jars/。注意权限hdfs dfs -chmod -R 755 /spark-jars。3.4 圆周率与 WordCount 的输入输出准备两个案例的成败80% 取决于数据路径是否正确。圆周率Pi无需外部数据纯计算。但需确保--master yarn和--deploy-mode client正确。WordCount必须有真实的 HDFS 输入文件。# 创建输入目录 hdfs dfs -mkdir -p /data/input # 生成测试文件10MB模拟真实日志 dd if/dev/urandom of/tmp/test.txt bs1M count10 # 转成可读文本用 base64 避免乱码 base64 /tmp/test.txt | head -n 10000 /tmp/wordcount-input.txt # 上传到 HDFS hdfs dfs -put /tmp/wordcount-input.txt /data/input/ # 验证 hdfs dfs -ls /data/input/ # 输出目录必须为空或不存在Spark 不会覆盖 hdfs dfs -rm -r /data/output/wordcount注意/data/input/wordcount-input.txt的路径必须和spark-submit命令中的--class org.apache.spark.examples.SparkPiPi或--class org.apache.spark.examples.JavaWordCountWordCount所期望的参数位置严格匹配。官方示例中WordCount 的第一个参数就是输入路径。4. 实操过程详解从提交到结果每一步都拆解现在环境配好了数据放好了我们进入最激动人心的环节敲命令看结果。但别急着复制粘贴我要带你“读懂”每一条命令背后的意图以及它在 YARN 架构中触发了什么。4.1 圆周率案例纯计算的压力探针标准命令client 模式$SPARK_HOME/bin/spark-submit \ --master yarn \ --deploy-mode client \ --class org.apache.spark.examples.SparkPi \ --driver-memory 1g \ --executor-memory 2g \ --executor-cores 2 \ --num-executors 2 \ $SPARK_HOME/examples/jars/spark-examples_2.12-3.1.2.jar \ 10逐行解析--master yarn告诉 Spark“别自己起 Master去找 YARN 的 ResourceManager”。此时 Spark 会读取HADOOP_CONF_DIR下的yarn-site.xml获取yarn.resourcemanager.hostname和端口。--deploy-mode clientDriver 进程运行在你当前这台机器提交机上。好处是你能直接看到Pi is roughly 3.141592653589793这样的最终结果也能实时看到INFO DAGScheduler: Job 0 finished: reduce at SparkPi.scala:38, took 12.345 s这类关键日志。--class org.apache.spark.examples.SparkPi指定主类。注意包名org.apache.spark.examples这是 Spark 官方示例 jar 的固定结构。--driver-memory 1gDriver 进程的 JVM 堆内存。它不参与计算只负责调度1G 足够。设太大浪费设太小如512m可能在收集大量结果时 OOM。--executor-memory 2g --executor-cores 2 --num-executors 2这是给 YARN 的“资源订单”。Spark 会向 RM 申请1 个 AM Container默认 1g 内存 2 个 Executor Container每个 2g 内存 2 vCores。RM 根据yarn.scheduler.capacity.root.default.maximum-capacity和当前队列使用率决定是否批准。$SPARK_HOME/examples/jars/spark-examples_2.12-3.1.2.jar这是 Spark 自带的示例 jar。注意后缀_2.12-3.1.2表示它编译时用的 Scala 2.12Spark 3.1.2。如果你的集群 Scala 版本是 2.11必须下载对应版本否则java.lang.NoClassDefFoundError: scala/Product。10这是 SparkPi 的唯一参数表示“用 10 个 task 并行估算”每个 task 生成 100000 个随机点。数值越大精度越高但耗时越长。执行过程与关键日志解读当你敲下回车会发生以下连锁反应Spark Client 进程启动读取配置连接到 RM。RM 返回一个ApplicationId如application_1678886400000_0001并告知 AM 将在哪个 NM 上启动。Spark Client 在指定 NM 上启动 AM一个独立的 JVM 进程。AM 启动后立即向 RM 申请 2 个 Executor Container。RM 分配 Container 后AM 通知对应的 NM 启动 Executor。关键观察点此时打开 YARN Web UIhttp://rm-host:8088找到你的 Application点击进去。你会看到Running Containers: 1 (AM) 2 (Executors) 3说明资源已成功分配。Logs: 点击 AM 的 Logs能看到INFO ApplicationMaster: Registered signal handlers for [TERM, HUP, INT]证明 AM 健康。Diagnostics: 如果显示AM Container for appattempt_... exited with exitCode: -1000立刻去看 NM 的日志/var/log/hadoop-yarn/yarn-yarn-nodemanager-*.log90% 是java.lang.OutOfMemoryError: Java heap space说明yarn.nodemanager.resource.memory-mb设小了或者--executor-memory设大了。成功标志终端输出最后一行Pi is roughly 3.141592653589793且 YARN UI 中 Application State 为FINISHEDFinal Status 为SUCCEEDED。实操心得第一次跑 Pi建议把10改成2即spark-submit ... 2让它只用 2 个 task。这样启动快、失败快、日志少便于快速验证环境。等2能跑通再试10、100。4.2 WordCount 案例I/O 与 Shuffle 的全流程演练标准命令client 模式$SPARK_HOME/bin/spark-submit \ --master yarn \ --deploy-mode client \ --class org.apache.spark.examples.JavaWordCount \ --driver-memory 1g \ --executor-memory 2g \ --executor-cores 2 \ --num-executors 2 \ $SPARK_HOME/examples/jars/spark-examples_2.12-3.1.2.jar \ /data/input/wordcount-input.txt \ /data/output/wordcount与 Pi 的关键差异解析差异点Pi 案例WordCount 案例为什么重要输入参数10纯数字/data/input/wordcount-input.txtHDFS 路径Spark Driver 会调用org.apache.hadoop.fs.FileSystem.get()根据core-site.xml的fs.defaultFS构建 HDFS Client。路径错误直接报FileNotFoundException。输出参数无/data/output/wordcountHDFS 路径Spark 会在 Driver 端检查该路径是否存在。如果存在抛org.apache.hadoop.mapred.FileAlreadyExistsException。必须提前hdfs dfs -rm -r /data/output/wordcount。内部流程无 Shuffle只有reducemap-shuffle write-shuffle read-reduce这是检验 YARN 网络和 HDFS 稳定性的黄金路径。Shuffle write阶段Executor 会把中间数据写到本地磁盘spark.local.dir再由ExternalShuffleService如果启用或直接通过 HTTP 传输给下游 Executor。任何网络抖动都会导致FetchFailedException。执行过程与关键日志解读Driver 日志重点看INFO FileInputFormat: Total input paths to process : 1—— 确认 HDFS 文件被识别。INFO SparkContext: Starting job: saveAsTextFile at JavaWordCount.java:64—— Job 开始。INFO DAGScheduler: Job 0 finished: saveAsTextFile at JavaWordCount.java:64, took 8.765 s—— Job 成功。YARN UI 重点看点击 Application -ApplicationMaster-Logs搜索Shuffle。正常应看到INFO ShuffleBlockFetcherIterator: Started fetch from 2 blocksINFO ExternalShuffleClient: Connected to shuffle server如果启用了 ExternalShuffleService如果看到WARN NettyBlockTransferService: Failed to fetch block说明网络或磁盘问题。HDFS 输出验证hdfs dfs -ls /data/output/wordcount # 应看到 _SUCCESS 和 part-00000 文件 hdfs dfs -cat /data/output/wordcount/part-00000 | head -20 # 应看到类似 the 1234 and 876 的词频统计常见失败场景与速查现象日志线索根本原因解决方案java.io.FileNotFoundException: File does not exist: /data/input/wordcount-input.txtDriver 日志HDFS 路径不存在或core-site.xml的fs.defaultFS指向错误集群hdfs dfs -ls /data/input/确认文件存在检查HADOOP_CONF_DIR下的core-site.xmlorg.apache.hadoop.mapred.FileAlreadyExistsException: Output directory /data/output/wordcount already existsDriver 日志输出目录已存在hdfs dfs -rm -r /data/output/wordcountContainer exited with a non-zero exit code 143YARN UI 中 Container 日志Executor 被 YARN Kill通常因为内存超限yarn.nodemanager.vmem-pmem-ratio触发降低--executor-memory或调大yarn.nodemanager.vmem-pmem-ratio默认 2.1FetchFailedException: Failed to fetch map outputExecutor 日志Shuffle 网络失败可能是 NM 间防火墙未开或spark.shuffle.service.enabledtrue但yarn.nodemanager.aux-servicesmapreduce_shuffle,spark_shuffle未配置检查yarn-site.xml中yarn.nodemanager.aux-services是否包含spark_shuffle并确认spark.shuffle.service.port端口开放提示WordCount 的JavaWordCount类是 Java 版本如果你用 Scala可用org.apache.spark.examples.ScalaWordCount参数相同。5. 深度问题排查与独家避坑指南那些文档里不会写的细节跑了 Pi 和 WordCount看似成功了但真正的挑战在“稳定运行”。我在某公司支撑 Spark 作业时遇到过最诡异的问题同一个spark-submit命令周一能跑通周二就卡在Connecting to AM持续 10 分钟后超时。日志里没有任何 ERROR只有 INFO。最后发现是周一凌晨运维同学重启了 ZooKeeper而 YARN 的 HA 配置中yarn.resourcemanager.zk-address指向的 ZK 节点列表里有一个节点 DNS 解析变慢导致 RM 切换时 Client 连接超时。这种问题官方文档绝不会提。下面是我整理的、来自真实战场的“避坑锦囊”。5.1 “AM Container exited with exitCode: -1000” 的终极排查树这个错误码是 Spark on YARN 的“万能错误”但它背后有清晰的根因分类。我画了一棵排查树按出现频率排序exitCode: -1000 ├── 1. AM 自身内存不足最常见 │ ├── 现象YARN UI 中 AM Container 的 Logs 里有 java.lang.OutOfMemoryError: Java heap space │ └── 解决在 spark-defaults.conf 中添加 spark.yarn.am.memory 2g或提交时加 --conf spark.yarn.am.memory2g ├── 2. Hadoop 配置文件缺失或错误 │ ├── 现象AM Logs 里有 java.net.UnknownHostException: namenode 或 java.lang.ClassNotFoundException: org.apache.hadoop.hdfs.DistributedFileSystem │ └── 解决确认 HADOOP_CONF_DIR 环境变量指向正确的 etc/hadoop 目录且该目录下有 core-site.xml, hdfs-site.xml, yarn-site.xml ├── 3. Kerberos 认证失败开启 Kerberos 时 │ ├── 现象AM Logs 里有 javax.security.auth.login.LoginException: Unable to obtain password from user │ └── 解决提交命令必须带 --principal your-principalREALM --keytab /path/to/keytab且 keytab 文件权限为 400 ├── 4. YARN 队列资源不足 │ ├── 现象YARN UI 中 Application State 为 ACCEPTED长时间不变成 RUNNING │ └── 解决yarn queue -status root.default 查看队列使用率yarn top 查看实时资源调整 yarn.scheduler.capacity.root.default.maximum-capacity 或提交到其他队列 └── 5. NM 磁盘空间不足 ├── 现象NM 日志/var/log/hadoop-yarn/yarn-yarn-nodemanager-*.log里有 No space left on device └── 解决清理 /var/log/hadoop-yarn/ 和 /hadoop/yarn/local/YARN 本地目录实操心得exitCode: -1000的日志永远先看 AM 的 Logs而不是 Driver 或 Executor 的。因为 AM 是第一个启动的容器它失败了后面什么都别想跑。5.2 “Shuffle Fetch Failed” 的网络诊断三板斧Shuffle 是 Spark 的心脏也是最脆弱的部分。当看到FetchFailedException不要慌按顺序执行第一板斧确认spark.shuffle.service.enabled是否启用如果为true生产推荐YARN 的 NM 必须配置yarn.nodemanager.aux-servicesmapreduce_shuffle,spark_shuffle且spark.shuffle.service.port7337默认端口在所有 NM 上开放。检查命令netstat -tuln | grep 7337必须看到LISTEN。如果为false默认Shuffle 由 Executor 自己提供 HTTP 服务此时需确保spark.blockManager.port默认 7079端口开放且 NM 间网络互通。第二板斧检查 HDFS Block Location 与 NM 主机名是否匹配执行hdfs fsck /data/input/wordcount-input.txt -files -blocks -locations输出中每个 Block 的Locations:应该列出具体的主机名如node1.cluster.local。登录到该主机执行hostname -f必须与fsck输出的主机名完全一致大小写、域名后缀都不能差。不一致会导致 Spark 认为“数据不在本地”强制走网络 Fetch而如果网络不通就失败。第三板斧用telnet直接测试网络连通性假设fsck显示 Block 在node3而你的 Executor 在node2上运行。在node2上执行telnet node3 7337如果启用了 shuffle service或 telnet node3 7