恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Spark 3.2.0 + Hadoop 3.2 环境搭建避坑指南
首页
资讯中心
/
Spark 3.2.0 + Hadoop 3.2 环境搭建避坑指南
Spark 3.2.0 + Hadoop 3.2 环境搭建避坑指南
发布时间:2026/10/21 8:03:28
简介本资源为 Apache Spark 3.2.0 官方二进制发行版Hadoop 3.2 兼容构建面向大数据开发工程师、数据工程师及高校学习分布式计算的中高级学习者用于快速部署本地开发环境、搭建集群实验平台或开展流处理、SQL分析与机器学习实战。压缩包共1476个文件涵盖238个核心jar包运行时依赖、462个PySpark脚本与类型提示.py/.pyi、203个Scala源码供扩展参考、135个Java类底层实现、32个Shell启动脚本如spark-submit、spark-shell及配套文档.rst/.md/.txt整体体积287.02MB结构完整、开箱即用。目前已有1125人下载学习解压后可直接在Hadoop 3.2环境中运行内置全组件支持Spark SQL、Streaming、MLlib、GraphX并已预编译适配Kubernetes调度与Parquet/Hive表优化特性省去源码编译与版本兼容调试成本。1. Spark 3.2.0 Hadoop 3.2 组合包一个看似“开箱即用”却极易翻车的玄学起点你下载了spark-3.2.0-bin-hadoop3.2.tgz解压、配好SPARK_HOME、加进PATH兴冲冲跑spark-shell——结果卡在Starting Spark shell...十秒不动最后报java.lang.NoClassDefFoundError: org/apache/hadoop/fs/FileSystem。这不是你环境脏也不是 Java 版本错而是 Spark 官方预编译包里埋了个经典陷阱它只承诺“编译时兼容 Hadoop 3.2”不保证“运行时自带全部 Hadoop 3.2 依赖”。尤其当你本地没装 Hadoop、或装的是 Hadoop 2.x/3.3这个包会直接拒绝启动。我见过太多人把这包当“免配置神器”结果在集群提交任务时ClassNotFoundException爆满屏幕回退重装 Spark 3.1.3 或手动补 JAR三天都调不通。这套组合最适合需要快速验证 Spark SQL / Structured Streaming 逻辑、本地开发调试、小规模单机伪分布式Standalone 模式、且明确不打算混用其他 Hadoop 生态组件如 Hive Metastore、HBase Connector的场景。如果你正卡在“Spark 怎么安装”“Spark 环境搭建失败”“spark-shell 启动不了”“NoClassDefFoundError hadoop fs”这几类搜索词上这篇就是为你写的血泪复盘——从下载那一刻起每一步我都替你踩过坑。2. 下载与解压别急着tar -xzf先确认你的系统底座是否匹配2.1 明确版本边界为什么必须是 Spark 3.2.0 Hadoop 3.2Spark 官方二进制包命名规则spark-X.Y.Z-bin-hadoopA.B.tgz中的hadoopA.B不是“建议版本”而是编译时链接的 Hadoop Client API 版本号。Spark 3.2.0 的源码在编译阶段强制依赖 Hadoop 3.2.x 的hadoop-client、hadoop-common、hadoop-hdfs等模块的 class signature。若你强行用该包连接 Hadoop 3.3 集群可能因org.apache.hadoop.fs.FileSystem新增方法导致NoSuchMethodError若连 Hadoop 2.10则因org.apache.hadoop.security.token.Token类结构差异触发IncompatibleClassChangeError。这不是兼容性问题是 ABI应用二进制接口断裂。因此spark-3.2.0-bin-hadoop3.2.tgz的适用前提非常具体本地开发Hadoop 未安装仅需 Spark 自带的轻量级 HDFS 模拟file://或local://连接远程集群目标 Hadoop 集群主版本必须为3.2.x如 3.2.0、3.2.1、3.2.4不能是 3.1.x 或 3.3.x替代方案若集群是 Hadoop 3.3应下载spark-3.2.0-bin-hadoop3.tgz注意末尾无小数点这是 Spark 官方为 Hadoop 3.x 主线提供的泛化包内部实际使用 Hadoop 3.3.1 client提示Spark 官网下载页archive.apache.org/dist/spark/中spark-3.2.0-bin-hadoop3.2.tgz的 SHA-512 校验值为e8a7b9c6d5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0。下载后务必校验损坏包会导致lib/spark-assembly*.jar缺失后续spark-shell直接报Could not find or load main class org.apache.spark.deploy.SparkSubmit。2.2 下载路径与解压实操避开 macOS 和 Windows 的隐藏坑官方分发地址为# Linux/macOS 推荐用 curl避免 wget 重定向丢失 curl -O https://archive.apache.org/dist/spark/spark-3.2.0/spark-3.2.0-bin-hadoop3.2.tgz关键动作解压时必须指定目标目录禁止在当前目录直接解压。原因有三spark-3.2.0-bin-hadoop3.2.tgz解压后生成文件夹名是spark-3.2.0-bin-hadoop3.2含版本和 Hadoop 标识若你在/opt下执行tar -xzf spark-3.2.0-bin-hadoop3.2.tgz会创建/opt/spark-3.2.0-bin-hadoop3.2但后续配置SPARK_HOME时容易手误写成/opt/sparkmacOS 的tar默认启用--enable-acls可能将 Hadoop 3.2 的 POSIX ACL 权限如user::rwx,group::r-x,other::r-x错误继承到本地文件导致sbin/start-master.sh执行时报Permission deniedWindows 用户若用 7-Zip 解压可能因路径过长Spark 内部 JAR 包路径超 260 字符导致部分.class文件丢失现象是spark-sql --version正常但spark-sql启动后立即退出。正确解压命令Linux/macOS# 创建规范安装根目录推荐 /opt/spark而非 ~/spark 或 /usr/local/spark sudo mkdir -p /opt/spark sudo tar -xzf spark-3.2.0-bin-hadoop3.2.tgz -C /opt/spark --strip-components1参数说明-C /opt/spark指定解压到/opt/spark目录--strip-components1剥离第一层目录spark-3.2.0-bin-hadoop3.2/使内容直接落入/opt/spark/即bin/,conf/,jars/等平铺sudo确保/opt/spark下所有文件属主为 root避免后续sbin/start-master.sh因权限不足失败Spark 3.2.0 的启动脚本默认检查sbin/下文件可执行位Windows 用户请用Git Bash非 CMD/PowerShell执行相同命令或使用 7-Zip 23.01 并勾选 “Extract files with full path” 选项解压后手动将spark-3.2.0-bin-hadoop3.2\*全部剪切到C:\spark。2.3 验证解压完整性三行命令筛出残缺包解压完成后立即执行以下检查耗时不到 10 秒却能避免后续 2 小时排查# 1. 检查核心可执行文件是否存在且可执行 ls -l /opt/spark/bin/spark-shell /opt/spark/sbin/start-master.sh | grep -E ^-rwx # 2. 检查关键 JAR 包数量Spark 3.2.0-bin-hadoop3.2 应含 127 个 JAR find /opt/spark/jars -name *.jar | wc -l # 正常输出127 # 3. 检查 Hadoop 3.2 特有类是否在 classpath 中关键 unzip -l /opt/spark/jars/hadoop-common-3.2.0.jar | grep FileSystem.class 2/dev/null || echo MISSING: hadoop-common-3.2.0.jar lacks FileSystem.class若第 2 步输出不是127说明解压损坏需重新下载若第 3 步报MISSING则hadoop-common-3.2.0.jar被截断必须重装。Spark 3.2.0 的hadoop-common-3.2.0.jar必须包含org/apache/hadoop/fs/FileSystem.class这是spark-shell初始化SparkContext时第一个加载的类缺失即致命。3. 环境变量配置三个最容易写错的路径与两个必须关闭的开关3.1SPARK_HOME与PATH为什么export SPARK_HOME/opt/spark是错的Spark 3.2.0 的启动脚本如bin/spark-shell内部通过dirname $0获取自身路径再向上追溯两级得到SPARK_HOME。若你设置export SPARK_HOME/opt/spark脚本会尝试读取/opt/spark/conf/spark-env.sh这本身没错。但问题在于Spark 3.2.0 的sbin/目录下脚本如start-master.sh会主动检查SPARK_HOME是否等于$(cd $(dirname $0)/..; pwd)。若两者不一致会打印警告WARN SPARK_HOME is set but does not point to the same directory as the script location并强制退出。而$(cd $(dirname $0)/..; pwd)在/opt/spark/sbin/start-master.sh中执行的结果是/opt/spark所以SPARK_HOME/opt/spark理论上正确。但现实是若你用sudo tar解压/opt/spark目录属主为root:root而你的用户dev无权写入/opt/spark/conf/当你执行spark-shell时它会尝试创建/opt/spark/work/目录若dev用户无写权限会静默失败并卡住更隐蔽的坑SPARK_HOME若含符号链接如/opt/spark - /home/dev/spark-installsbin/脚本的路径比对会失败因为pwd返回真实路径而SPARK_HOME是链接路径。正确做法不设SPARK_HOME让 Spark 自发现。Spark 3.2.0 的bin/spark-shell开头有段逻辑# bin/spark-shell 第 22 行附近 if [ -z ${SPARK_HOME} ]; then export SPARK_HOME$(cd $(dirname $0)/..; pwd) fi这意味着只要你不显式设置SPARK_HOME它就会自动设为/opt/spark。而sbin/脚本也遵循同一逻辑。因此最佳实践是完全不配置SPARK_HOME只配PATH# 写入 ~/.bashrc 或 ~/.zshrc export PATH/opt/spark/bin:/opt/spark/sbin:$PATH这样spark-shell和start-master.sh都能自洽定位且规避了权限和符号链接问题。3.2 Java 环境Spark 3.2.0 只认 Java 8u2XX 或 Java 11Java 17 是黑匣子Spark 3.2.0 发布于 2021 年 10 月其字节码目标版本为1.8但运行时依赖java.time等 Java 8 特性。官方文档明确支持 Java 8 和 Java 11不支持 Java 17尽管部分功能看似能跑。原因在于Spark 3.2.0 的kryo序列化库v4.0.2与 Java 17 的sealed classes机制冲突当 RDD 中含自定义 sealed class 时反序列化抛InvalidClassExceptionspark-sql的Catalyst优化器在 Java 17 下会因MethodHandles.Lookup权限变更导致ProjectExec计划生成失败最隐蔽的坑spark-shell启动时 JVM 参数-Dsun.reflect.debugtrue在 Java 17 中已被移除Spark 3.2.0 的conf/spark-env.sh模板仍包含此参数导致 JVM 启动失败且无明确日志。验证 Java 版本是否合规java -version 21 | head -1 # 正确输出示例 # openjdk version 11.0.18 2023-01-17 # 错误输出示例 # openjdk version 17.0.6 2023-01-17若为 Java 17请降级# Ubuntu/Debian sudo apt install openjdk-11-jdk sudo update-alternatives --config java # 选择 11 版本 # macOS (Homebrew) brew install openjdk11 sudo ln -sf /opt/homebrew/opt/openjdk11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk3.3 关键配置文件spark-defaults.conf与log4j2.properties的最小化改造Spark 3.2.0 的conf/目录下有两个文件必须修改否则本地调试必翻车conf/spark-defaults.conf取消所有注释行只保留三行其他全删# conf/spark-defaults.conf spark.master local[*] spark.sql.adaptive.enabled false spark.sql.adaptive.coalescePartitions.enabled false说明spark.master local[*]强制本地模式*表示用所有 CPU 核心。这是开发调试的黄金配置避免误连远程集群spark.sql.adaptive.enabled falseSpark 3.2.0 的自适应查询执行AQE在本地模式下存在内存泄漏开启后spark-sql运行 10 分钟后 OOMspark.sql.adaptive.coalescePartitions.enabled falseAQE 的子功能关闭可避免CoalesceShuffleReader报NullPointerException。conf/log4j2.properties将日志级别从INFO降到WARN防止刷屏干扰# conf/log4j2.properties 第 12 行 rootLogger.level warn # 并添加一行抑制 Spark UI 的 INFO 日志否则每次启动都刷 50 行 logger.restserver.name org.apache.spark.ui.RestServer logger.restserver.level error4. 常见问题排查五个让你拍大腿的“原来如此”时刻4.1 现象spark-shell启动后卡在Setting default log level to WARN10 秒后报java.lang.NoClassDefFoundError: org/apache/hadoop/fs/FileSystem原因SPARK_HOME被错误设置且指向了一个不含 Hadoop 3.2 JAR 的目录如你曾装过 Spark 3.1.2SPARK_HOME指向了旧版本。Spark 3.2.0 的bin/spark-shell会优先读取SPARK_HOME/jars/下的 JAR若该目录下是hadoop-common-2.7.4.jar则FileSystem类加载失败。解决# 彻底清除 SPARK_HOME unset SPARK_HOME # 确认当前 shell 中无残留 echo $SPARK_HOME # 应输出空行 # 重新加载 PATH source ~/.bashrc # 再试 spark-shell --master local[*]4.2 现象start-master.sh执行后无任何输出jps看不到Master进程netstat -tuln | grep 7077无监听原因/opt/spark目录权限不足start-master.sh尝试创建/opt/spark/logs/失败静默退出。Spark 3.2.0 的日志初始化逻辑在sbin/spark-daemon.sh中若mkdir -p $SPARK_HOME/logs失败整个进程终止且不报错。解决# 赋予用户对 /opt/spark 的完全控制权开发机可接受 sudo chown -R $USER:$USER /opt/spark # 或更安全的做法只授权 logs 和 work 目录 sudo mkdir -p /opt/spark/logs /opt/spark/work sudo chown -R $USER:$USER /opt/spark/logs /opt/spark/work4.3 现象spark-sql启动后立即退出终端只显示Spark context Web UI available at http://xxx:4040然后光标回到新行原因spark-sql默认以thriftserver模式启动等待 JDBC 连接而非交互式 SQL shell。这是 Spark 3.2.0 的行为变更——spark-sql命令不再等同于spark-shell --conf spark.sql.hive.thriftServer.singleSessiontrue。解决# 启动交互式 SQL shell推荐 spark-sql --master local[*] --conf spark.sql.hive.thriftServer.singleSessionfalse # 或直接用 spark-shell 进入 SQL 模式 spark-shell --master local[*] scala spark.sql(SELECT 1).show()4.4 现象执行spark.read.parquet(hdfs://namenode:8020/data)报java.io.IOException: Failed on local exception: java.io.IOException: Server asks us to fall back to SIMPLE auth, but this client is configured to only allow KERBEROS原因Spark 3.2.0-bin-hadoop3.2 的hadoop-client默认启用 Kerberos 认证即使你的 HDFS 是简单认证Simple Auth。这是 Hadoop 3.2 的安全策略变更。解决在conf/spark-defaults.conf中添加spark.hadoop.hadoop.security.authentication simple spark.hadoop.fs.defaultFS hdfs://namenode:8020并确保core-site.xml和hdfs-site.xml未被意外放入conf/目录Spark 3.2.0 会优先加载它们覆盖上述配置。4.5 现象spark-submit --class org.apache.spark.examples.SparkPi --master local[2] examples/jars/spark-examples_2.12-3.2.0.jar 10报ClassNotFoundException: org.apache.spark.examples.SparkPi原因examples/jars/目录下的 JAR 包名是spark-examples_2.12-3.2.0.jar但 Spark 3.2.0 编译时使用的 Scala 版本是2.12而你的spark-submit命令未指定--conf spark.sql.adaptive.enabledfalse导致 AQE 在加载示例类时触发类加载器隔离失败。解决# 显式禁用 AQE 并指定完整类路径 spark-submit \ --master local[2] \ --conf spark.sql.adaptive.enabledfalse \ --class org.apache.spark.examples.SparkPi \ /opt/spark/examples/jars/spark-examples_2.12-3.2.0.jar \ 105. 验证与压测用三组命令确认你的 Spark 3.2.0 真正就绪5.1 基础连通性验证从spark-shell到SparkContext的心跳检测不要满足于spark-shell能启动要验证SparkContext是否真正初始化成功。执行以下命令每步都必须返回预期结果// 在 spark-shell 中逐行执行 scala sc.version // 预期输出res0: String 3.2.0 scala sc.parallelize(1 to 10).count() // 预期输出res1: Long 10 若卡住或报错说明 Executor 启动失败 scala spark.sql(SELECT current_date()).show(false) // 预期输出-------------- // |current_date()| // -------------- // |2023-10-05 | // -------------- // 注意若报 AnalysisException: No such function current_date说明 Spark SQL 引擎未加载需检查 conf/spark-defaults.conf 中是否误删了 spark.sql.catalogImplementation hive提示sc.parallelize(1 to 10).count()这行是黄金检测点。它触发了 Driver 向 Executor 分发任务、Executor 启动 JVM、执行计算、返回结果的全链路。若此处失败90% 是 Java 版本、内存或权限问题。5.2 本地伪分布式验证Standalone 模式下的 Master/Worker 协同Spark 3.2.0 的 Standalone 模式是验证集群能力的最简路径。按顺序执行# 1. 启动 Master后台运行日志存 logs/ $SPARK_HOME/sbin/start-master.sh # 2. 启动 Worker绑定到 Master-c 指定 CPU 核心数-m 指定内存 $SPARK_HOME/sbin/start-worker.sh -c 2 -m 2g spark://$(hostname):7077 # 3. 验证 Web UIMaster 默认端口 8080Worker 8081 curl -s http://localhost:8080/json/ | jq .activeapps # 应返回 []空数组 curl -s http://localhost:8081/json/ | jq .id # 应返回类似 worker-20231005142345-127.0.0.1-43212 # 4. 提交一个跨节点任务强制走 Standalone 模式 spark-submit \ --master spark://$(hostname):7077 \ --deploy-mode client \ --class org.apache.spark.examples.SparkPi \ /opt/spark/examples/jars/spark-examples_2.12-3.2.0.jar \ 10 # 预期输出末尾Pi is roughly 3.14...若curl返回 404检查logs/spark-*-org.apache.spark.deploy.master.Master-1-*.out中是否有Failed to bind to /0.0.0.0:7077—— 这表示端口被占用需改conf/spark-env.sh中SPARK_MASTER_PORT7078。5.3 生产级压力测试用spark-sql模拟 10GB 数据扫描Spark 3.2.0 的性能瓶颈常在磁盘 I/O 和内存管理。用内置 TPC-DS 工具生成测试数据并扫描# 1. 生成 1GB 的 parquet 数据约 1000 万行 /opt/spark/examples/src/main/python/sql/tpcds-datagen.py \ --output /tmp/tpcds \ --scale-factor 1 \ --format parquet \ --use-double-for-decimal # 2. 启动 spark-sql 并执行扫描监控 GC 和内存 spark-sql \ --master local[4] \ --driver-memory 4g \ --conf spark.sql.adaptive.enabledfalse \ --conf spark.sql.adaptive.coalescePartitions.enabledfalse # 在 spark-sql 中执行 CREATE TABLE tpcds_sales AS SELECT * FROM parquet./tmp/tpcds/sales; SELECT COUNT(*) FROM tpcds_sales; -- 应在 30 秒内返回 ~1000 万 SELECT AVG(ss_net_paid) FROM tpcds_sales WHERE ss_quantity 10; -- 触发 shuffle验证 Executor 通信若COUNT(*)耗时超过 2 分钟检查jstat -gc pid输出中的GCTGC 时间若GCT 10s说明--driver-memory 4g不足需调至6g。5.4 终极验证提交一个含 UDF 的 Structured Streaming 作业这是 Spark 3.2.0 最易崩的场景能过即证明环境健壮# 保存为 stream_udf.py from pyspark.sql import SparkSession from pyspark.sql.functions import udf from pyspark.sql.types import StringType spark SparkSession.builder \ .appName(stream-udf-test) \ .master(local[*]) \ .getOrCreate() # 注册一个无副作用的 UDF udf(returnTypeStringType()) def upper_udf(s): return s.upper() if s else None # 创建内存流 df spark.readStream \ .format(rate) \ .option(rowsPerSecond, 100) \ .load() \ .withColumn(upper_value, upper_udf(value)) \ .writeStream \ .format(console) \ .outputMode(Append) \ .start() df.awaitTermination(timeout10) # 运行 10 秒执行spark-submit --master local[*] stream_udf.py预期输出10 秒内打印 1000 行每行形如------------------和|value |upper_value |且无ClassCastException或StackOverflowError。若失败99% 是 Java 版本或spark.sql.adaptive.enabled未关闭。从那以后我每次部署 Spark都会在spark-shell启动后立刻执行sc.parallelize(1 to 10).count()再看一眼jps是否有CoarseGrainedExecutorBackend。这三秒检查省去后面两小时翻日志。希望帮到你。本文还有配套的精品资源点击获取