Spark 3.2.0与Hadoop 3.2集群搭建及任务提交实战指南
简介spark-3.2.0-bin-hadoop3.2.tgz 是 Apache Spark 3.2.0 面向 Hadoop 3.2 环境编译的官方二进制发行包适合大数据开发工程师、数据科学家及高校学生用于搭建本地或集群实验环境解决分布式计算、结构化查询与机器学习任务的运行需求。包内共 1476 个文件以 462 个 Python 脚本、238 个 jar 依赖、203 个 Scala 与 135 个 Java 源码为主辅以 txt 说明、sh/cmd 启动脚本、parquet/orc/csv 示例数据及少量图片与配置模板压缩包约 287.02MB解压后可直接调用 spark-submit、spark-shell、pyspark 等入口。该版本在性能、SQL 优化、PySpark 一致性、Kubernetes 原生支持及内存管理上均有改进并新增时间旅行等特性。目前已有 1123 人学习下载适合希望快速上手 Spark 3.2 生态、验证 DataFrame 与流处理能力的读者参考使用。1. spark-3.2.0-bin-hadoop3.2.tgz一个压缩包背后是一整套离线大数据环境很多人第一次看到spark-3.2.0-bin-hadoop3.2.tgz这个文件名是在内网服务器的/opt/software目录里或者某份交接文档的附件清单中。它不是一个普通压缩包而是 Apache Spark 官方为「已装好 Hadoop 3.2.x 的集群」预编译好的二进制发行版。文件名里的bin表示开箱即用hadoop3.2表示它默认对接 Hadoop 3.2 的客户端依赖省去了自己编译的麻烦。你拿到它通常意味着要做三件事搭一套能跑 Spark 的 Hadoop 环境、把 Spark 解压配置好、然后提交第一个任务验证链路。这套流程在离线机房、教学实验、课程设计里反复出现也是「spark集群搭建」「hadoop伪分布式搭建」这类搜索词长期高热的原因。下面按我实际部署的顺序把每一步拆开讲清楚。2. 先理清 Spark 与 Hadoop 的依赖关系再动手解压2.1 为什么是 hadoop3.2 这个后缀而不是随便一个 HadoopSpark 本身不存储数据它依赖外部存储和资源调度。spark-3.2.0-bin-hadoop3.2.tgz里的hadoop3.2指的是编译时链接的 Hadoop 客户端版本。Spark 运行时需要读写 HDFS、访问 YARN这些都要通过 Hadoop 的 Java 客户端库完成。如果集群实际装的是 Hadoop 3.2.x用这个包最省心如果集群是 Hadoop 2.7用这个包会在连接 HDFS 时报NoSuchMethodError或ClassNotFoundException因为 Hadoop 3.x 的 API 有变动。常见做法是先确认hadoop version的输出再决定用哪个 Spark 预编译包。我一般会保持 Spark 包里的 Hadoop 版本与集群主版本一致小版本差异可以容忍大版本跨越必须换包。2.2 解压前要确认的三件事JDK、主机名、免密在解压之前有三项环境检查不做后面一定翻车。第一JDK 版本。Spark 3.2.0 要求 Java 8 或 Java 11推荐 Java 8因为 Hadoop 3.2 对 Java 11 的支持还不完整。用java -version确认输出里带1.8.0即可。第二主机名解析。集群里每个节点都要能通过主机名互相 ping 通/etc/hosts里要有完整映射否则 Spark 启动时会卡在Resolving hostname阶段。第三SSH 免密。Hadoop 的启动脚本依赖免密登录Spark 的 standalone 模式也依赖。用ssh localhost测试不输密码能进去才算通过。# 检查 JDK 版本必须是 1.8 java -version 21 | grep 1.8.0 # 检查主机名解析三台机器都要能互相 ping 通 cat /etc/hosts ping -c 2 hadoop-master # 配置免密登录在 master 上执行 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id hadoop-master ssh-copy-id hadoop-slave1 ssh-copy-id hadoop-slave2上面这段命令的逻辑是先确认 Java 版本再确认网络层的主机名可达最后把公钥分发到所有节点。ssh-keygen的-P 表示空密码-f指定密钥路径。ssh-copy-id会把公钥追加到目标机器的~/.ssh/authorized_keys。参数上唯一要注意的是主机名必须和/etc/hosts里写的一致大小写敏感。如果ssh localhost还需要密码检查~/.ssh权限是否为 700authorized_keys是否为 600。2.3 解压与目录规划别把 Spark 和 Hadoop 混在一起解压本身很简单但目录规划决定了后面维护成本。我一般把 Hadoop 和 Spark 放在/opt下各自独立目录用软链接指向具体版本。这样升级时只改软链接环境变量不用动。# 解压 Spark 到 /opt tar -zxvf spark-3.2.0-bin-hadoop3.2.tgz -C /opt/ # 建立软链接方便版本切换 ln -s /opt/spark-3.2.0-bin-hadoop3.2 /opt/spark # 确认目录结构 ls /opt/spark # 应该看到 bin、sbin、conf、jars、examples 等目录tar -zxvf中-z表示 gzip 解压-x解压-v显示过程-f指定文件。解压后bin目录放的是spark-submit、spark-shell等用户命令sbin放的是start-master.sh、start-workers.sh等集群管理脚本conf放配置文件jars放依赖包。软链接不是必须的但强烈建议因为后面配环境变量时写/opt/spark比写完整版本号清爽得多。3. 配置 Spark 对接 Hadoop从环境变量到 spark-env.sh3.1 环境变量怎么配才不互相覆盖Spark 读取环境变量的顺序是先看conf/spark-env.sh再看系统环境变量。所以最稳妥的做法是把所有关键变量都写进spark-env.sh而不是只依赖/etc/profile。需要配的变量有四个JAVA_HOME、HADOOP_CONF_DIR、SPARK_MASTER_HOST、SPARK_LOCAL_IP。# 编辑 /opt/spark/conf/spark-env.sh cp /opt/spark/conf/spark-env.sh.template /opt/spark/conf/spark-env.sh vi /opt/spark/conf/spark-env.sh # 加入以下内容 export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export HADOOP_CONF_DIR/opt/hadoop/etc/hadoop export SPARK_MASTER_HOSThadoop-master export SPARK_LOCAL_IPhadoop-master export SPARK_WORKER_MEMORY4g export SPARK_WORKER_CORES2HADOOP_CONF_DIR是关键它告诉 Spark 去哪里找core-site.xml和hdfs-site.xml。如果不配这个Spark 提交到 YARN 时会报Cannot locate Hadoop configuration。SPARK_MASTER_HOST只在 standalone 模式下生效指定 Master 节点的主机名。SPARK_LOCAL_IP用于绑定网卡多网卡机器上必须指定否则 Worker 注册到 Master 时可能上报错误的 IP。SPARK_WORKER_MEMORY和SPARK_WORKER_CORES控制每个 Worker 能分配的资源按机器实际配置调整一般留出 20% 给系统。3.2 对接 YARN 时 core-site.xml 和 yarn-site.xml 的必改项如果 Spark 要跑在 YARN 上Hadoop 侧的配置必须提前改好。core-site.xml里fs.defaultFS要指向 NameNode 地址yarn-site.xml里yarn.resourcemanager.hostname要指向 ResourceManager 所在机器。这两个文件改完要分发到所有节点然后重启 Hadoop。!-- core-site.xml 关键项 -- property namefs.defaultFS/name valuehdfs://hadoop-master:9000/value /property !-- yarn-site.xml 关键项 -- property nameyarn.resourcemanager.hostname/name valuehadoop-master/value /property property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /propertyfs.defaultFS的端口 9000 是 NameNode 的 RPC 端口要和hdfs-site.xml里dfs.namenode.rpc-address一致。yarn.nodemanager.aux-services必须包含mapreduce_shuffle否则 YARN 启动 NodeManager 时会失败。改完配置后用scp分发到所有节点然后stop-yarn.sh再start-yarn.sh。验证方式是jps在 master 上看到ResourceManager在 slave 上看到NodeManager。3.3 启动 Spark 集群并验证 Web UI配置完成后用sbin/start-all.sh启动 standalone 集群。这个脚本会启动 Master 和所有 Worker。启动后用jps检查进程Master 节点应有MasterWorker 节点应有Worker。然后访问http://hadoop-master:8080看 Web UI确认 Worker 数量和你启动的一致。# 启动 Spark standalone 集群 /opt/spark/sbin/start-all.sh # 检查进程 jps # Master 节点应看到 Master # Worker 节点应看到 Worker # 停止集群 /opt/spark/sbin/stop-all.shstart-all.sh实际调用的是start-master.sh和start-workers.sh。如果 Worker 没起来先看logs/目录下对应日志常见原因是SPARK_LOCAL_IP没配导致绑定失败或者 SSH 免密没配好导致启动脚本无法远程执行。Web UI 的 8080 端口如果被占用可以在spark-env.sh里加SPARK_MASTER_WEBUI_PORT8081改端口。4. 提交第一个任务从 local 模式到 YARN 模式4.1 用 spark-shell 做最小验证集群起来后别急着写复杂代码先用spark-shell跑一个 local 模式的任务确认 Spark 本身没问题。spark-shell是 Scala 交互式终端启动时会自动创建SparkContext。# 启动 local 模式 spark-shell /opt/spark/bin/spark-shell --master local[2] # 在 shell 里执行 val data Seq(1,2,3,4,5) val rdd sc.parallelize(data) val sum rdd.reduce(_ _) println(sSum is: $sum) # 应输出 Sum is: 15--master local[2]表示用本地两个线程模拟集群不连接任何外部 Master。sc.parallelize把本地集合转成 RDDreduce做聚合。这一步能跑通说明 JDK、Scala 版本、Spark 核心包都没问题。如果报java.lang.NoClassDefFoundError检查JAVA_HOME是否配错如果报Connection refused说明--master指向了不存在的 Master 地址。4.2 提交到 YARN 的完整命令与参数含义验证 local 模式后用spark-submit提交到 YARN。这是生产环境最常用的方式。下面是一个读 HDFS 文件、做词频统计、写回 HDFS 的完整示例。# wordcount.py from pyspark import SparkConf, SparkContext conf SparkConf().setAppName(WordCount) sc SparkContext(confconf) # 读 HDFS 文件 lines sc.textFile(hdfs://hadoop-master:9000/input/data.txt) # 切词、映射、聚合 counts lines.flatMap(lambda line: line.split( )) \ .map(lambda word: (word, 1)) \ .reduceByKey(lambda a, b: a b) # 写回 HDFS counts.saveAsTextFile(hdfs://hadoop-master:9000/output/wordcount) sc.stop()# 提交到 YARN /opt/spark/bin/spark-submit \ --master yarn \ --deploy-mode cluster \ --executor-memory 2g \ --executor-cores 1 \ --num-executors 2 \ /opt/spark/apps/wordcount.py--master yarn表示用 YARN 调度。--deploy-mode cluster表示 Driver 跑在 YARN 容器里适合生产client模式 Driver 跑在提交机器上适合调试。--executor-memory控制每个 Executor 的内存--executor-cores控制每个 Executor 的 CPU 核数--num-executors控制 Executor 数量。这三个参数决定了任务并行度和资源占用设大了会排队设小了跑得慢。一般按「总核数 / executor-cores」估算 num-executors内存不超过 NodeManager 可用内存的 80%。4.3 任务提交后看什么日志、UI、退出码提交后不要只等结果。先看终端输出的application_编号然后用yarn logs -applicationId 编号查日志。同时打开 YARN ResourceManager Web UI默认 8088 端口看任务状态是ACCEPTED、RUNNING还是FAILED。如果失败重点看stderr里的Caused by部分。常见错误有Container killed by YARN for exceeding memory limits说明 executor 内存设小了FileNotFoundException说明 HDFS 输入路径不对ClassNotFoundException说明依赖包没打进去。# 查看 YARN 应用日志 yarn logs -applicationId application_1234567890_0001 # 查看应用列表 yarn application -list # 杀掉卡住的应用 yarn application -kill application_1234567890_0001yarn logs会输出所有容器的日志信息量大建议重定向到文件再搜关键字。yarn application -list能看到所有运行中和已完成的应用。-kill用于终止失控任务。退出码方面spark-submit返回 0 表示成功非 0 表示失败但注意 cluster 模式下 Driver 在 YARN 里提交命令的退出码只代表提交动作是否成功不代表任务成功必须看 YARN 应用状态。5. 避坑与排查那些让我加班到凌晨的配置问题5.1 现象Worker 节点启动后立刻退出Web UI 看不到 Worker原因通常是SPARK_LOCAL_IP没配或配错。多网卡机器上Spark 默认会选第一个非回环网卡如果那个网卡不可达Worker 注册到 Master 就会失败。解决方式是在spark-env.sh里显式指定SPARK_LOCAL_IP为实际通信网卡的 IP然后重启集群。验证方法是netstat -tlnp | grep 7077看 Master 是否在监听以及 Worker 日志里是否有Registering worker字样。5.2 现象提交到 YARN 时报Cannot locate Hadoop configuration原因是HADOOP_CONF_DIR没配或者配的路径下没有core-site.xml和hdfs-site.xml。Spark 需要这两个文件来解析 HDFS 地址和 YARN 地址。解决方式是在spark-env.sh里加export HADOOP_CONF_DIR/opt/hadoop/etc/hadoop并确认该目录下文件存在且内容正确。如果用了--files参数分发配置文件注意路径要写绝对路径。5.3 现象任务跑一半报Container killed by YARN for exceeding memory limits原因是 Executor 内存超限。Spark 的内存模型分执行内存和存储内存加上 JVM 自身开销实际占用会比--executor-memory设的值高。解决方式是调大--executor-memory或者加--conf spark.yarn.executor.memoryOverhead1024增加堆外内存。另外检查代码里是否有collect()把大量数据拉到 Driver这种操作在集群模式下极易 OOM。5.4 现象spark-shell启动报NoSuchMethodError或ClassNotFoundException原因是 Spark 包里的 Hadoop 版本和集群实际 Hadoop 版本不一致。比如用hadoop3.2的 Spark 包去连 Hadoop 2.7 的集群HDFS 客户端 API 不兼容。解决方式是换用与集群 Hadoop 大版本一致的 Spark 预编译包或者自己用-Phadoop-2.7重新编译。检查方式是hadoop version和ls /opt/spark/jars | grep hadoop对比版本号。5.5 现象HDFS 写入时报Permission denied原因是提交任务的用户对 HDFS 目标路径没有写权限。Hadoop 默认用提交者的用户名做身份认证如果该用户在 HDFS 上不存在或没有目录权限就会拒绝。解决方式是用hdfs dfs -mkdir -p /user/$(whoami)创建用户目录并chown给该用户或者在core-site.xml里把hadoop.http.staticuser.user设为有权限的用户。生产环境不建议关权限检查应该走 Kerberos 或正确配置用户映射。6. 进阶技巧用 spark-submit 的 --files 和 --archives 管理依赖实际项目里Python 脚本往往依赖第三方库或者需要分发配置文件。spark-submit的--files和--archives就是干这个的。--files分发普通文件--archives分发压缩包并自动解压。我一般把虚拟环境打包成venv.tar.gz用--archives分发然后在代码里指定PYSPARK_PYTHON指向解压后的解释器。# 打包虚拟环境 tar -czf venv.tar.gz venv/ # 提交时分发 /opt/spark/bin/spark-submit \ --master yarn \ --deploy-mode cluster \ --archives hdfs:///deps/venv.tar.gz#venv \ --conf spark.yarn.appMasterEnv.PYSPARK_PYTHON./venv/bin/python \ --conf spark.executorEnv.PYSPARK_PYTHON./venv/bin/python \ /opt/spark/apps/wordcount.py--archives的#venv表示解压后目录名为venvYARN 会把压缩包分发到每个容器的当前工作目录并解压。spark.yarn.appMasterEnv.PYSPARK_PYTHON指定 Driver 用的 Python 解释器spark.executorEnv.PYSPARK_PYTHON指定 Executor 用的。两个都要设否则 Driver 和 Executor 可能用不同版本的 Python导致序列化错误。验证方式是看 YARN 日志里 Python 版本输出是否一致。另一个技巧是动态资源分配。在spark-env.sh里开spark.dynamicAllocation.enabledtrue配合spark.shuffle.service.enabledtrueSpark 会根据任务负载自动增减 Executor。这对共享集群特别有用避免一个任务占着资源不干活。但要注意动态分配下--num-executors会被忽略初始 Executor 数由spark.dynamicAllocation.initialExecutors控制。# 开启动态资源分配 --conf spark.dynamicAllocation.enabledtrue \ --conf spark.shuffle.service.enabledtrue \ --conf spark.dynamicAllocation.minExecutors1 \ --conf spark.dynamicAllocation.maxExecutors10 \ --conf spark.dynamicAllocation.initialExecutors2spark.shuffle.service.enabled必须在 YARN 的yarn-site.xml里也配yarn.nodemanager.aux-services加上spark_shuffle并分发spark-version-yarn-shuffle.jar到所有 NodeManager 的 classpath。这一步漏了动态分配会报Shuffle service not found。我踩过这个坑当时只改了 Spark 侧配置忘了 YARN 侧结果任务一直卡在Waiting for shuffle service。最后说一个验证方法用spark-submit提交任务后在 YARN UI 里点进 ApplicationMaster 的日志搜PYSPARK_PYTHON和SPARK_LOCAL_DIRS确认环境变量生效。再在 Spark UI默认 4040 端口cluster 模式下在 ApplicationMaster 里看 Stage 和 Task 的分布如果 Task 数远小于预期说明分区数不够需要repartition或调整spark.default.parallelism。这些细节决定了任务跑得快不快而不是能不能跑。我自己的习惯是每次搭完新集群先跑一个spark-submit的 wordcount把--files、--archives、动态分配都试一遍确认链路全通再上业务代码。这样后面出问题能快速定位是环境问题还是代码问题。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →