ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spark 3.2.0 环境搭建与调优实战:从 tgz 解压到集群提交

Spark 3.2.0 环境搭建与调优实战:从 tgz 解压到集群提交 简介spark-3.2.0-bin-hadoop3.2.tgz 是 Apache Spark 3.2.0 面向 Hadoop 3.2 环境编译的官方二进制发行包适合大数据开发工程师、数据科学家及高校学生直接部署使用免去源码编译环节解压即可在已有 Hadoop 3.2 集群上提交作业。压缩包共收录 1476 个文件整体约 287.02MB以 462 个 py 与 88 个 pyi 构成 PySpark 接口238 个 jar 承载核心运行库另有 203 个 scala、135 个 java 源码及 91 个 txt、51 个 rst 文档并附带 sh、cmd 启动脚本与 parquet、orc、avro 等示例数据覆盖 Spark Core、SQL、Streaming、MLlib、GraphX 全部组件。该版本在 Tungsten 代码生成、Catalyst 优化器、PySpark 性能、Kubernetes 原生支持及内存管理上均有改进并新增时间旅行查询等能力。目前已有 1123 人学习下载可帮助读者快速搭建本地或集群实验环境对照源码与示例理解各模块结构为后续调优与二次开发提供完整基线。1. spark-3.2.0-bin-hadoop3.2.tgz一个压缩包背后要落地的四件事很多人第一次看到spark-3.2.0-bin-hadoop3.2.tgz这个文件名会以为它只是一个下载链接里的字符串。实际上它是一份已经替你编译好的发行包Spark 3.2.0 版本预编译时绑定的 Hadoop 客户端是 3.2 系列。把它解压、配好环境变量你就能在本地或集群上跑起 Spark不需要自己拿 Maven 从头编译。它解决的核心问题是「省掉编译这一步」让你把精力放在写作业、调参数、跑数据分析案例上。这篇笔记面向三类人刚装完 Hadoop 伪分布式、准备往上叠 Spark 的手里已经有这个 tgz、但不确定该配哪些环境变量的以及想搞清楚bin-hadoop3.2这个后缀到底约束了什么的人。下面按「这个包是什么 → 怎么解压配置 → 怎么验证跑通 → 坑在哪 → 怎么调优」的顺序讲每一步都给可抄的命令和参数。2. 先搞清 bin-hadoop3.2 后缀它绑定了什么、没绑定什么2.1 发行包命名规则与依赖边界Spark 官方下载页的文件名格式是spark-版本-bin-Hadoop版本.tgz。这里的bin表示二进制发行版hadoop3.2表示这个包在编译时链接的 Hadoop 客户端库版本是 3.2.x。它意味着两件事第一包里jars/目录下已经带了对应版本的 Hadoop 客户端 jar你不需要额外把 Hadoop 的 jar 拷进来第二它只是「客户端绑定」不等于你必须在本地装一个 Hadoop 3.2 集群。这是最容易混淆的点。bin-hadoop3.2里的 Hadoop 是作为 Spark 读写 HDFS、访问 YARN 的客户端依赖存在的。你可以只装 Spark用local[*]模式跑完全不碰 HDFS也可以把它接到一个 Hadoop 3.x 集群上。真正需要对齐的是如果你要连的远端集群是 Hadoop 3.2那这个包开箱即用如果远端是 Hadoop 2.7官方建议换bin-hadoop2.7的包否则可能出现 RPC 协议不兼容的报错。选型上我一般这样判断本地学习、跑 spark 数据分析案例直接用bin-hadoop3.2配local[*]最省事要接公司已有集群先问清 NameNode 的 Hadoop 版本再决定用哪个后缀的包。别小看这个后缀接错版本时抛出的异常往往藏在NoSuchMethodError里排查起来很费时间。2.2 解压前必须确认的三项环境动手之前先确认三样东西能省掉后面一半的报错。第一是 JDK。Spark 3.2.0 要求 Java 8 或 Java 11官方主推 Java 8。用java -version确认输出里带1.8.0最稳。Java 17 在这个版本上会碰到模块访问限制不建议。第二是 Scala 版本。这个包默认带的是 Scala 2.12写代码或引第三方包时要用 2.12 编译的版本混用 2.11 会报NoClassDefFoundError。第三是主机名解析。Spark 启动时会解析主机名如果/etc/hosts里没有本机主机名对应的记录会卡在启动阶段或报UnknownHostException。用hostname拿到主机名确认hostname -i能返回一个 IP。# 确认 JDK 版本期望输出包含 1.8 java -version # 确认主机名能被解析两个命令返回的 IP 应一致 hostname hostname -i # 如果 hostname -i 返回 127.0.1.1 或报错检查 /etc/hosts cat /etc/hosts上面三条命令是排查环境的最低成本手段。java -version看的是运行时版本不是JAVA_HOME指向的版本两者不一致时以实际运行的为准。hostname -i返回异常时在/etc/hosts里补一行127.0.0.1 你的主机名通常能解决。3. 从 tgz 到能跑解压、环境变量与最小验证3.1 解压与目录结构说明拿到 tgz 后解压位置建议放在一个有写权限、路径不含空格的目录比如/opt或用户家目录下的soft。路径带空格会让后续脚本解析出问题这是血泪经验。# 假设 tgz 已下载到当前目录 tar -zxvf spark-3.2.0-bin-hadoop3.2.tgz -C /opt # 进入解压后的目录确认结构 cd /opt/spark-3.2.0-bin-hadoop3.2 ls解压后你会看到几个关键目录bin/放的是spark-shell、spark-submit、pyspark这些入口脚本sbin/放的是集群启停脚本比如start-all.shconf/是配置目录模板文件都带.template后缀jars/是全部依赖 jar。理解这四个目录后面配什么都心里有数。3.2 环境变量配置与生效验证环境变量是新手最容易配漏的一环。最少要配SPARK_HOME和把bin加进PATH。如果还要跑 PySpark得让 Python 能找到 Spark 的库。# 编辑当前用户的 shell 配置bash 用 .bashrczsh 用 .zshrc vim ~/.bashrc # 在文件末尾追加以下内容 export SPARK_HOME/opt/spark-3.2.0-bin-hadoop3.2 export PATH$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin # 跑 PySpark 时让 Python 能找到 Spark 的 Python 库 export PYTHONPATH$SPARK_HOME/python:$SPARK_HOME/python/lib/py4j-0.10.9-src.zip:$PYTHONPATH # 让配置立即生效 source ~/.bashrc # 验证 echo $SPARK_HOME which spark-shellSPARK_HOME必须指向解压后的根目录不是bin子目录指错了spark-submit会找不到jars。PYTHONPATH里的 py4j 版本号要和你解压目录python/lib/下的实际文件名一致别照抄先ls看一眼。which spark-shell能返回路径说明PATH生效了。3.3 用 spark-shell 跑通最小作业配置完先别急着搭集群用本地模式验证包本身是好的。local[*]表示用本机所有 CPU 核心跑不依赖任何外部集群。# 启动 spark-shell本地模式指定 master spark-shell --master local[*]进入交互界面后跑一段最小代码验证 RDD 和 DataFrame 两条路径都通。// 用本地集合造一个 RDD做词频统计 val data Seq(spark hadoop, spark tgz, hadoop spark) val rdd sc.parallelize(data) val counts rdd.flatMap(_.split( )).map((_, 1)).reduceByKey(_ _) counts.collect().foreach(println) // 验证 DataFrame 路径读取一个本地 JSON val df spark.read.json(/opt/spark-3.2.0-bin-hadoop3.2/examples/src/main/resources/people.json) df.show() df.printSchema()第一段代码验证的是 Spark Coreparallelize把本地集合转成分布式数据集flatMap切词map打标reduceByKey聚合。第二段验证 Spark SQLread.json读取 JSON 文件show打印内容printSchema看推断出的结构。两段都跑通说明这个 tgz 解压、环境变量、运行时依赖都没问题。people.json是包自带的示例数据路径按你实际解压位置调整。提示spark-shell默认启动时会打印一堆 INFO 日志看着乱但正常。想安静点把conf/log4j.properties.template复制成log4j.properties把 root 日志级别从 INFO 改成 WARN。4. 接 Hadoop 与集群模式配置项怎么填、怎么验证4.1 伪分布式场景下的对接配置如果你已经按 hadoop 伪分布式搭建的流程装好了 Hadoop想让 Spark 读写 HDFS需要让 Spark 知道 NameNode 地址。有两种做法一是把 Hadoop 的core-site.xml和hdfs-site.xml拷到 Spark 的conf/下二是直接在 Spark 配置里指定。我一般用第一种配置集中不容易漏。# 把 Hadoop 的配置文件软链或拷贝到 Spark conf 目录 ln -s /opt/hadoop/etc/hadoop/core-site.xml $SPARK_HOME/conf/core-site.xml ln -s /opt/hadoop/etc/hadoop/hdfs-site.xml $SPARK_HOME/conf/hdfs-site.xml # 确认 HDFS 可访问 hdfs dfs -ls / # 用 spark-shell 读 HDFS 上的文件 spark-shell --master local[*]进入 shell 后用spark.read.text(hdfs://namenode:port/path)读一个 HDFS 文件。能读出来说明客户端对接成功。这里的关键是core-site.xml里的fs.defaultFS要指向正确的 NameNode端口别写错Hadoop 3.x 默认是 8020 或 9000取决于你的配置。4.2 Standalone 集群的启动与 worker 注册Spark 自带的 Standalone 模式适合学习和中小规模场景。启动前先在conf/spark-env.sh里配好 master 相关参数。# 从模板复制配置文件 cp $SPARK_HOME/conf/spark-env.sh.template $SPARK_HOME/conf/spark-env.sh # 编辑加入以下内容 export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export SPARK_MASTER_HOST你的主机名或IP export SPARK_MASTER_PORT7077 export SPARK_WORKER_CORES2 export SPARK_WORKER_MEMORY2gSPARK_MASTER_HOST填主机名时要保证所有节点都能解析这个名字。SPARK_WORKER_CORES和SPARK_WORKER_MEMORY是每个 worker 能提供给 executor 的资源上限设得比物理资源大不会报错但会引发资源争抢。配好后启动。# 启动 master 和所有 worker $SPARK_HOME/sbin/start-all.sh # 查看进程应能看到 Master 和 Worker jps # 打开 Web UI 确认 worker 已注册 # 浏览器访问 http://master-host:8080jps输出里出现Master和Worker两个进程说明启动成功。Web UI 的 8080 端口能看到 worker 列表和可用核心数。如果 worker 没注册上八成是SPARK_MASTER_HOST填了localhost导致 worker 连不上 master改成实际主机名即可。4.3 提交作业到集群并观察资源分配集群起来后用spark-submit提交一个作业观察 executor 是否按预期分配。# 提交 Spark 自带的 Pi 计算示例到 Standalone 集群 $SPARK_HOME/bin/spark-submit \ --master spark://master-host:7077 \ --class org.apache.spark.examples.SparkPi \ --executor-memory 1g \ --total-executor-cores 2 \ $SPARK_HOME/examples/jars/spark-examples_2.12-3.2.0.jar \ 100--master指向 Standalone 的 7077 端口--executor-memory是每个 executor 的内存--total-executor-cores是所有 executor 加起来用的核心数。作业跑完后Web UI 的 4040 端口应用运行期间能看到 stage 和 task 的分布。如果作业一直卡在WAITING多半是集群可用资源小于你申请的量把--executor-memory调小再试。5. 避坑与排查五个真实翻车现场5.1 启动报 UnknownHostException现象spark-shell或spark-submit启动时报java.net.UnknownHostException: 主机名进程直接退出。原因系统解析不了当前主机名Spark 在初始化通信地址时拿不到有效 IP。常见于虚拟机克隆后主机名变了但/etc/hosts没同步。解决hostname拿到当前主机名在/etc/hosts里补一行127.0.0.1 主机名保存后重试。集群场景下每个节点都要补。5.2 版本不匹配导致 NoSuchMethodError现象提交作业时报java.lang.NoSuchMethodError堆栈指向 Hadoop 或 Scala 相关类。原因Spark 编译时绑定的依赖版本和你运行时引入的版本冲突。典型是bin-hadoop3.2的包接了 Hadoop 2.x 集群或者用户 jar 里带了不同版本的 Scala 库。解决先确认远端集群 Hadoop 版本换对应后缀的 Spark 包用户 jar 用--packages或--jars显式指定避免和 Spark 自带 jar 冲突。用spark-submit --verbose能看到实际加载的 jar 列表。5.3 内存不足引发 executor 被 kill现象作业跑到一半Web UI 上 executor 消失日志里出现Container killed by YARN for exceeding memory limits或 executor 心跳超时。原因spark.executor.memory设得偏小或者spark.memory.fraction默认值下缓存数据挤占了执行内存触发 OOM。解决先调大--executor-memory再考虑调spark.memory.fraction默认 0.6和spark.memory.storageFraction默认 0.5。如果数据倾斜严重光加内存治标不治本得先处理倾斜的 key。5.4 日志级别刷屏掩盖真实错误现象控制台被 INFO 日志淹没真正的 ERROR 一闪而过排查困难。原因默认 log4j 配置是 INFO 级别Spark 内部组件日志量大。解决复制log4j.properties.template为log4j.properties把log4j.rootCategory改成WARN, console。需要看细节时再临时调回 INFO别一直开着。5.5 路径含空格或中文导致脚本解析失败现象spark-submit报找不到 jar 或配置文件路径明明存在。原因解压目录或 jar 路径里有空格、中文shell 脚本在拼接参数时被截断。解决把 Spark 解压到纯英文、无空格的路径比如/opt/spark-3.2.0-bin-hadoop3.2。已经装了的改SPARK_HOME指向新路径重新source配置。6. 调优与验证把 spark-submit 参数调到能打6.1 三个必调参数与取值思路Spark 作业跑得慢或跑不稳八成和这三个参数有关。它们不是孤立的要一起看。参数作用常见取值思路spark.executor.memory每个 executor 的堆内存从 2g 起按数据量和缓存需求往上加别超过单机物理内存的 75%spark.executor.cores每个 executor 占用的核心数2 到 5 之间太大影响 HDFS 并发读写太小并行度不够spark.sql.shuffle.partitionsshuffle 后分区数默认 200小数据量时调小到 10 到 50大数据量按核心数 2 到 3 倍设调这三个参数的顺序是先定 executor 内存和核心再根据总核心数算并行度最后调 shuffle 分区数。spark.sql.shuffle.partitions默认 200 在小数据量下会生成大量空 task启动开销比计算还大这是很多人忽略的点。6.2 用 Web UI 验证调优效果调完参数别凭感觉用 Web UI 看数据。作业运行期间访问http://driver-host:4040重点看三个地方Stages 页面看每个 stage 的 task 数和耗时分布Storage 页面看缓存占用了多少内存Executors 页面看每个 executor 的 GC 时间和 shuffle 读写量。如果某个 stage 的 task 耗时差异极大说明数据倾斜加内存没用得改分区键或加盐。如果 GC 时间占比超过 10%说明内存给少了或对象创建太频繁。如果 shuffle 读远大于写检查是不是重复 shuffle 了同一份数据。6.3 一个可复用的验证习惯我自己的习惯是每次调完参数先用一个小数据集跑一遍确认作业能正常结束、结果正确再上全量数据。小数据集跑通不代表全量没问题但小数据集都跑不通全量一定翻车。验证时固定用同一个作业、同一份输入只改参数这样对比才有意义。另外spark-submit加--verbose能看到最终生效的配置比翻文档猜默认值靠谱。参数优先级是代码里SparkConf设的 spark-submit命令行传的 spark-defaults.conf里的 默认值。搞不清哪个生效时--verbose一跑就清楚。这套流程我从第一次配 Spark 用到现在最深的教训是别跳过最小验证直接上集群。本地local[*]跑通那一步花不了十分钟但能帮你排除掉环境变量、JDK 版本、主机名解析这些和集群无关的干扰项。后面再出问题范围就小得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表