学习笔记做到第 19 节,数仓的项目框架已经越来越清楚了。前面把 Hadoop、Hive、Zookeeper 这些基础组件铺好之后,接下来就是给数仓准备真正的计算引擎了。刚开始我也有点疑惑——Hive 本身可以做数据分析,为什么还要单独搞一套 Spark?真把 Spark 装起来、配置完、跑通任务之后才明白,数据仓库的运行环境里,Spark 不是“可选项”,而是后续 DW 层清洗、指标计算、灵活分析这一整套流程里提效的关键角色。这篇笔记就把我在数据仓库运行环境搭建过程中,Spark 安装及配置这一块的完整操作和踩坑记录整理出来。不管你是在跟着数仓教程做环境搭建,还是准备在公司集群里给数仓配一个能用的计算引擎,这篇内容都能帮你省下不少折腾的时间。
很多人以为装 Spark 就是下载解压改一下环境变量,实际上真正决定后面的任务能不能稳定跑起来的,恰恰是那些容易忽略的细节——版本匹配、内存规划、部署模式选择、配置文件的参数含义。这些我会一项一项拆开讲。
1. 数仓环境里为什么一定要装 Spark 计算引擎
1.1 Spark 在数仓搭建中的核心定位
数据仓库跑批任务最重的部分就是 ETL 和数据加工。传统方案里,Hive 默认用 MapReduce 执行 SQL,小批量数据还能忍,一旦 QPS 上来、数据量到了千万级别,MapReduce 轮番落盘的机制就会让作业慢得让人抓狂。
Spark 在数仓环境里做的事情,就是用内存计算替代大量的磁盘中间结果。同一个 SQL 语句,Hive on MR 可能要跑 20 分钟,换上 Spark 引擎之后可能两三分钟就出结果。这种提升不是一点半点,而是直接改变整个数仓的调度周期。尤其在做数仓分层的时候,DWD 层要清洗明细数据、DWS 层要做轻度汇总、ADS 层要出应用指标,每一层都是大量的转换和聚合逻辑,Spark 的 DataFrame API 和 Spark SQL 能把这些逻辑写得既简洁又高效。
还有一点值得注意:在数仓环境里,Spark 并不是孤立存在的。它需要和 Hive 共用一个元数据层,所以你要让 Spark 能通过 Hive Metastore 读取表结构信息,这样 Spark SQL 才能直接操作 Hive 里的表。这也是为什么安装 Spark 的时候,必须先确认 Hive 的元数据配置是对的、MySQL 驱动是在的,不然 Spark 装完了也只能跑一些自娱自乐的小程序,接不到数仓的表里。
1.2 Spark 版本与 Hadoop、JDK 的兼容匹配
这一节要放在所有操作之前思考,因为版本选错了,后面全白干。很多新手在这一步栽跟头,下载了最新版 Spark,结果集群里 JDK 是 1.7,或者 Hadoop 是 2.6,跑起来各种 NoSuchMethodError。
我的建议是先去集群里查一下现有版本:
java -version hadoop version hive --version如果是跟着多数数仓课程走的环境,比较常见的组合是 JDK 1.8 + Hadoop 3.1.3 + Hive 3.1.2,这种情况下选 Spark 3.0.0 或 Spark 3.3.x 都可以,因为 Spark 3.x 官方要求 JDK 8 起步,本身也针对 Hadoop 3 做了预编译包。
下载的时候注意看包名。像spark-3.3.0-bin-hadoop3.tgz和spark-3.3.0-bin-without-hadoop.tgz就是两个完全不同的东西。前者已经内置了 Hadoop 客户端相关依赖,你直接解压就能跑;后者不带 Hadoop 依赖,需要自己在运行时指定 HADOOP_CONF_DIR 和外部的 Hadoop 包。初学阶段直接用bin-hadoop3这种包最省心。
另一个常见的误区是纠结 Scala 版本。Spark 3.x 内部是用 Scala 2.12 编译的,运行时会自动加载内置的 Scala 库,所以你不需要在系统里单独安装 Scala 再配 SCALA_HOME。这一点和 Spark 2.x 时代有区别,如果你看的老教程里要求先装 Scala,在 Spark 3.x 环境下可以跳过。
1.3 部署模式选定:Standalone 还是 YARN
数仓跑批任务最终大概率要往 YARN 上放,因为 YARN 是 Hadoop 集群统一的资源管理器,能同时协调 MapReduce、Spark、Flink 这些任务的内存和 CPU。不过在环境搭建练习阶段,我建议先装一套 Standalone 模式把 Spark 本身的机制摸熟,再切到 YARN 模式跑正式任务。
Standalone 模式的好处是 Spark 自己管理 Master 和 Worker,不需要依赖 YARN 的资源调度器,Web UI 上能直观看到每个 Worker 分到了多少内存和核数,适合排查问题。而 YARN 模式的好处是资源统一管理,不需要单独关心 Worker 内存配置,Executor 的调度完全交给 YARN。在数仓项目里,生产环境基本都是 YARN 模式。
所以我的实际做法是:先把 Standalone 集群起来并跑通测试任务,然后在 spark-defaults.conf 里把默认 master 指向 yarn,平时提交任务时以 YARN 模式为主,两种模式都保留,切换起来也方便。
2. 安装前的环境盘点与依赖确认
2.1 主机规划与目录约定
数仓环境搭建一般会准备多台机器,这里以经典的三节点为例来演示:hadoop102、hadoop103、hadoop104。之前安装 Hadoop 和 Hive 时我已经形成了一套目录规范,这次装 Spark 也沿用同样的套路:
- 软件安装包统一放在
/opt/software目录下 - 解压后的程序放在
/opt/module目录下 - 数据和日志另放路径,不跟程序混在一起
这样做的好处非常实际。第一,多个组件在同样的目录层级下,环境变量配置写起来非常规整;第二,后面做集群分发时只用同步/opt/module下的对应目录就行,不用到处找安装位置;第三,出了问题想删掉重装,直接移除一个目录即可,不会污染系统的其他部分。
比如我这台机器上下载的是spark-3.0.0-bin-hadoop3.2.tgz,解压之后的规范操作是把目录重命名为 spark,因为后面所有配置都引用了这个短名称,如果带着长长的版本号,写进 spark-env.sh 里的路径容易出错,看着也别扭:
cd /opt/software tar -zxvf spark-3.0.0-bin-hadoop3.2.tgz -C /opt/module cd /opt/module mv spark-3.0.0-bin-hadoop3.2 spark2.2 核对 JDK、Hadoop、Hive 的依赖是否就绪
Spark 安装前自己不会去检查你的 Hadoop 集群是否健康,但实际上 HDFS 的 NameNode 和 DataNode 必须正常运行,因为 Spark 后续要读写 HDFS 上的文件、提交历史事件日志到 HDFS、通过 Hive Metastore 读元数据。
在动手装 Spark 前,我建议先执行一遍下面的命令:
start-dfs.sh start-yarn.sh jps确保 NameNode、SecondaryNameNode、DataNode、ResourceManager、NodeManager 这些进程都在。同时确认 Hive Metastore 能正常连接:
hive --service metastore &如果 Hive 的元数据服务起不来,Spark SQL 后面即使配了 hive-site.xml 也连不上数仓的表。很多报错绕来绕去最后发现是 MySQL 里授权的问题,这一步提前验证能帮你把问题隔离在 Spark 之外。
2.3 确认 SSH 免密登录和主机名解析
Standalone 模式的 Master 要拉起多台机器的 Worker 进程,底层依赖 SSH 免密登录。如果在配置完 workers 文件之后启动失败,八成就是 hadoop103、hadoop104 这两台机器上的用户没有配好从 hadoop102 到它们的免密。
我当时在搭建 Hadoop 集群时已经配过免密登录,但 Spark 启动脚本有时会因为配置了不同的用户而失效。最简单的检查方式:
ssh hadoop103 date ssh hadoop104 date如果还需要输入密码,就把公钥重新分发一遍。这一步看起来和 Spark 本身没什么关系,但往往就是它让 Worker 起不来,而且日志里报错很隐晦。
还有主机名解析。Spark 的 Master 启动之后,会依赖反向解析把 hostname 映射到 IP。我在/etc/hosts里写了三段地址映射,同时确认每台机器的 hostname 命令输出和 hosts 表一致,避免出现主机名被解析成 127.0.0.1 的经典状况。
3. Spark 下载、解压与核心配置实操
3.1 下载 Spark 安装包时的注意事项
下载 Spark 时别直接去最新版本页面乱点,要确认几个信息:
- 是否需要预编译的 Hadoop 3 版本包
- 本机架构是 x86_64 还是 ARM
- 你用的 Hadoop 版本是否支持该 Spark 版本
在官方 Apache Archive 页面找到对应版本后,我会找名字里带bin-hadoop3的 tar.gz 包。比如:
spark-3.3.0-bin-hadoop3.tgz这一个文件集合了 Spark 本体和 Hadoop 客户端依赖,适合绝大多数课程练习和公司测试环境。下载完成后校验一下文件大小和 MD5,避免下载到残缺文件——这种问题很少见,但一旦发生,光排查解压报错就能耗掉半天时间。
3.2 配置 SPARK_HOME 环境变量
解压完成之后立刻改环境变量,这一步尽量放到最开始做,因为我后面启动 history server、提交任务、操作 spark-shell 都需要直接使用 spark-submit / spark-shell 命令,如果不配环境变量,就要老是用绝对路径。
编辑/etc/profile:
export SPARK_HOME=/opt/module/spark export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin刷新配置并验证:
source /etc/profile spark-submit --version验证的时候要注意,spark-submit --version只是打印版本日志,不意味着环境完全就绪。真正证明环境能用,是后面成功运行一个小任务。
这里我要多说一句:如果你在 Hadoop 的/etc/profile里也配置了类似export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin,那么 PATH 里会同时存在 Hadoop 和 Spark 的命令。Hadoop 和 Spark 都有start-all.sh脚本,并且都以 sbin 为目录名,执行命令时系统按 PATH 顺序优先找到谁就会执行谁,这就埋了一个很大的坑,后面我会专门说。
3.3 spark-env.sh 核心参数逐项说明
Spark 的配置集中在$SPARK_HOME/conf目录下。安装包默认只给示例文件,需要手动复制一份再改:
cd /opt/module/spark/conf cp spark-env.sh.template spark-env.sh我最先配置的是这个文件,因为 Standalone 模式下 Master 和 Worker 的核心运行参数都在这里。
一段典型的 spark-env.sh 配置如下:
# 设置 Java 安装路径,避免 shell 找不到 java export JAVA_HOME=/opt/module/jdk1.8 # Master 节点的主机名 export SPARK_MASTER_HOST=hadoop102 # Master 通信端口,默认 7077 export SPARK_MASTER_PORT=7077 # 每个 Worker 上启动的 Worker 实例数量 export SPARK_WORKER_INSTANCES=1 # 每个 Worker 分配给 Spark 的 CPU 核数 export SPARK_WORKER_CORES=4 # 每个 Worker 分配给 Spark 的内存大小 export SPARK_WORKER_MEMORY=8g这里有几个需要动脑子的地方。
SPARK_WORKER_MEMORY不能拍脑袋填。我当时的机器是每台 16G 内存,但 Hadoop、Hive、Zookeeper、MySQL 都跑在同一批节点上。如果我把 16G 全部塞给 Spark Worker,操作系统剩余内存可能直接打满,最终导致其他服务频繁 GC,甚至整个节点卡死。实际经验是,单机上预留 20% 到 30% 内存给系统和常驻服务,剩下的再给 Spark。16G 的机器给 Worker 分配 8G 是比较稳妥的起点,后续可以根据任务量往上调。
SPARK_WORKER_CORES也是一样的道理。要看物理机实际核数,同时考虑同一台机器上 YARN 的 NodeManager 也要占资源。如果 CPU 核数给太多,一个 Worker 同时跑多个 Executor 时反而可能因为线程切换拖慢速度。
还有个容易忽略的点:SPARK_WORKER_INSTANCES默认是 1。如果填 2,一台机器会启动两个 Worker 进程,分别独立申请资源和端口,这通常不是我们想要的。一个 Worker 进程配合多 Executor 才是常见做法。
3.4 workers 文件配置与集群分发
把conf/workers.template拷贝成conf/workers(Spark 3.0 之前的版本里这个文件叫 slaves,新版改名了,注意别继续照旧教程去配 slaves):
cp workers.template workers编辑 workers,填入你要启动 Worker 的节点:
hadoop102 hadoop103 hadoop104然后整目录分发到另外两台机器,确保每台机器的目录路径和配置完全一致:
xsync /opt/module/spark这里要注意,分发之后要检查 hadoop103 和 hadoop104 上的 spark-env.sh 里的SPARK_MASTER_HOST是不是也指向 hadoop102。因为 Spark 的 Worker 启动脚本会读取这个变量来连接 Master,如果每台机器的 spark-env.sh 里都写死了各自的主机名,Worker 就连不上 Master 了。
3.5 spark-defaults.conf 与历史日志配置
第一次把 Standalone 集群启动起来之后,我很快发现一个问题:Spark 应用跑完,再想看它的运行指标就找不到了。Spark 自带的 Web UI 只在应用运行期间展示,应用结束页面就关闭。对于数仓环境里频繁提交的批任务,没有历史运行记录会非常难受。
所以 Spark 安装好后,有一件事一定要顺手做掉——配置 History Server,让所有完成的任务日志都持久化到 HDFS 上,之后随时能回看每个 Stage 的耗时、Shuffle 量、GC 情况。
修改conf/spark-defaults.conf(从模板复制后编辑):
spark.eventLog.enabled true spark.eventLog.dir hdfs://hadoop102:8020/spark-history spark.history.fs.logDirectory hdfs://hadoop102:8020/spark-history配置里hdfs://hadoop102:8020这个地址要和你的 Hadoop NameNode 端口一致。如果不知道端口,可以查看core-site.xml里的fs.defaultFS配置。每套 Hadoop 环境的端口可能不一样,有的是 9000,有的是 9820,不是所有教程都恰好是 8020。
然后到 HDFS 上创建历史日志目录:
hdfs dfs -mkdir /spark-history在 spark-env.sh 中还加了历史服务器的内存相关配置:
export SPARK_HISTORY_OPTS="-Dspark.history.ui.port=18080 -Dspark.history.retainedApplications=20"spark.history.ui.port设成了 18080,是因为 8080 已经被 Spark Master 占了,历史服务器再用 8080 会冲突。
3.6 启动 Standalone 集群并验证 Web UI
启动方式这里特别强调一下。不要直接用start-all.sh,因为 Hadoop 的 sbin 目录下也有一个同名脚本,PATH 环境变量的优先级会导致你启动的根本不是 Spark。
我最终采用的是分别调用:
/opt/module/spark/sbin/start-master.sh /opt/module/spark/sbin/start-workers.sh启动后先检查进程:
jps正常会在 hadoop102 看到 Master 进程,在三个节点都看到 Worker 进程。同时访问http://hadoop102:8080,页面里能看到三个 Worker 的地址、各自分配到的 CPU 核数和内存。如果页面里 Worker 数量不对,先去对应节点看日志,大多数情况是免密登录或 spark-env.sh 里的SPARK_MASTER_HOST配错了。
4. 跑通 Spark 任务:从本地模式到 YARN 再到 SQL
4.1 spark-shell 快速验证环境可不可用
环境变量和配置文件都就位之后,先别急着提交大任务,用 spark-shell 做一次最基本的功能验证。
在 Standalone 模式下进入交互式环境:
spark-shell --master spark://hadoop102:7077启动过程如果卡在日志输出半天不动,多半是机器内存不足或端口连接失败。进入 shell 之后执行:
sc.parallelize(1 to 10).map(_ * 2).collect()如果能看到结果Array(2, 4, 6, 8, 10, 12, 14, 16, 18, 20),说明 Spark 的 Standalone 调度链路是通的。这一步不要跳,因为很多配置问题在交互式环境下暴露得最直观,而且错误日志直接打在终端,查看起来最方便。
4.2 用官方示例程序验证集群计算能力
Spark 自带几个示例程序,最常用的就是 SparkPi,通过蒙特卡洛算法计算圆周率。这个程序特别适合做环境验证,因为它逻辑简单,但能完整走一遍任务提交、Executor 分配、结果回传的全流程。
/opt/module/spark/bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master spark://hadoop102:7077 \ /opt/module/spark/examples/jars/spark-examples_2.12-3.0.0.jar \ 10提交之后打开http://hadoop102:4040,能看到当前正在运行的应用,点进去可以看 Executors 列表和每个 Executor 的资源分配情况。
跑完之后回到 spark-shell 的执行结果里确认 Pi 值输出。这一步完成了,说明 Spark 不光是“装好了”,而是真正能把任务分发到各个 Worker 上执行。
4.3 Spark on YARN 模式的两种部署方式对比
数仓场景里,我们最终要让 Spark 和 YARN 建立联系。在 spark-defaults.conf 里把默认 master 设为 yarn 之后,提交任务的命令会简洁很多:
spark-submit \ --class org.apache.spark.examples.SparkPi \ /opt/module/spark/examples/jars/spark-examples_2.12-3.0.0.jar \ 10Spark on YARN 有两种部署方式:
- client 模式:Driver 运行在提交任务的客户端机器上,适合交互式调试
- cluster 模式:Driver 由 YARN 分配在某个 NodeManager 的容器里运行,适合生产跑批
我用一个表格把它们的核心差异整理在这里:
| 对比项 | client 模式 | cluster 模式 |
|---|---|---|
| Driver 运行位置 | 提交任务的本机 | YARN 分配到的某个 NodeManager 容器 |
| 适用场景 | 调试、spark-shell | 生产环境跑批任务 |
| 与 YARN 交互 | 直接在客户端申请资源 | 通过 ApplicationMaster 再启动 Driver |
| 日志查看 | 直接看客户端终端 | 看 YARN 的 container 日志 |
| 推荐程度 | 开发阶段推荐 | 生产环境推荐 |
很多数仓项目里,Hive on Spark 和 Spark SQL 跑批都会用 cluster 模式,因为一旦 Driver 在客户端运行,客户端机器挂了任务就断了,而在 cluster 模式下 YARN 会负责状态跟踪和重启。
切到 YARN 模式之后,要注意 yarn-site.xml 中yarn.nodemanager.resource.memory-mb的参数配置。我在测试机上遇到过一次 Executor 起不来的问题,后来发现是 YARN 给 NodeManager 分配的总内存太少,Spark 的 Executor 申请不到足够的资源。解决办法是把 NodeManager 的总内存调大,同时让 Spark Executor 的内存加 overhead 不超过这个上限。
4.4 Spark SQL 对接 Hive 元数据
这是数仓环境里最关键的一步,也是很多人卡住的一步:让 Spark SQL 能直接操作 Hive 里的分层表。
需要做三件事。
第一件,把 Hive 的hive-site.xml拷贝到 Spark 的 conf 目录下:
cp /opt/module/hive/conf/hive-site.xml /opt/module/spark/conf/这样 Spark 才能读到 Hive Metastore 的地址和连接参数。
第二件,确认 MySQL 驱动在 Spark 的 jars 目录下。Spark 连接 Hive 元数据时,要通过 JDBC 访问 MySQL,如果mysql-connector-java的 jar 没放进来,启动 Spark SQL 时会直接报找不到驱动类的错误:
cp /opt/software/mysql-connector-java-5.1.49.jar /opt/module/spark/jars/注意版本,如果 MySQL 是 5.x 用 5.1.4x 的驱动;如果是 MySQL 8 要用对应的 8.x 驱动,驱动版本不对会在连接时报Public Key Retrieval is not allowed之类的错误,很折磨人。
第三件,重启 Spark 相关进程让配置生效。然后可以测试:
spark-sql --master yarn --deploy-mode client \ -e "show databases;"如果数仓里的几个数据库都列出来了,说明 Spark SQL 和 Hive 元数据已经打通。之后直接在 Spark SQL 里写的建表语句、查询语句都能落到数仓的分层表中,Spark 才能算是真正接入了数仓运行环境。
5. 常见问题排查与踩坑实录
5.1 start-all.sh 命令串台,启动的是 HDFS
这个坑十个人有九个人会踩。我在配置完环境变量后执行了start-all.sh,结果 console 里输出的启动线程情况很眼熟——是 Hadoop 的 NameNode 和 DataNode 在启动,Spark 的 Master 根本没起来。
原因很简单,PATH 环境变量中,Hadoop 的 sbin 目录排在 Spark 之前,系统先找到了 Hadoop 的 start-all.sh。解决办法也很简单:不要用裸命令,直接敲完整路径/opt/module/spark/sbin/start-master.sh和/opt/module/spark/sbin/start-workers.sh,或者把 Spark 的 sbin 在 PATH 里放到 Hadoop 前面。
5.2 Worker 内存参数过大导致进程崩溃
我朋友的集群配置的是 64G 内存的物理机,他按照网上随手搜的参数把SPARK_WORKER_MEMORY设成了 48g,结果 Worker 启动后连心跳都发不出去,偶尔还会触发系统 OOM。
因为一台机器上跑的不仅是 Spark Worker,还有 DataNode、NodeManager、Hive Metastore 等一堆常驻进程。操作系统本身也要留内存。后来我给他调成 32g,同时把 YARN 的 NodeManager 内存上限也做了匹配调整,所有进程都稳定了。这个原则就是:先算总账,再分配额。
5.3 Executor 启动失败,Container 不断退出
在 YARN 模式下跑任务时,日志里出现类似Container exited with a non-zero exit code 143的问题,看起来像是被人为杀掉了,其实是内存申请超过了容器限制。YARN 判断 Container 使用的物理内存超过了yarn.nodemanager.vmem-pmem-ratio的倍数就会直接把进程杀掉。
排查思路是四步:
- 用
yarn logs -applicationId <app_id>查看具体日志 - 确认
spark.executor.memory与spark.executor.memoryOverhead之和是否小于 NodeManager 总内存 - 检查 YARN 的
yarn.nodemanager.resource.memory-mb设置 - 检查容器是否开了太多 Executor,导致单容器堆内存乘数量超过了整机资源
我在实际项目里通常把 Executor 内存控制在 4G 到 8G,每个 Executor 配 2 到 4 个核,然后根据任务的数据量动态调整 Executor 数量。
5.4 Spark SQL 报错找不到 Hive 表
Spark SQL 启动成功,但运行show tables时报错说找不到库表,这种情况往往不是 Spark 的问题,而是 Hive Metastore 没有启动,或者 spark 里的 hive-site.xml 配置地址不对。
我建议先单独验证 Hive 侧:
hive --service metastore再在另一个终端执行hive -e "show databases;",确认 Hive 本身正常。确认没问题之后再检查 Spark 所在的节点是否能连通 Metastore 的 9083 端口:
nc -vz hadoop102 9083如果端口通,再检查 spark 的 jars 目录下有没有 mysql 驱动。这一套下来基本能把问题定位到具体环节。> 提示:对接 Hive 时如果报错信息里带Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient,优先怀疑 hive-site.xml 没拷贝到位或 Metastore 没起来。
5.5 历史服务器看不到已完成的作业
History Server 页面打开之后一直在加载,或者只能看到当前应用。这个问题排查方向集中在三个地方:
第一,HDFS 上的/spark-history目录必须存在,而且 Spark 的 history 配置和 spark-defaults.conf 里的事件日志目录要完全一致;
第二,spark-shell 和 spark-submit 跑任务时要确认spark.eventLog.enabled是 true,可以通过spark-submit --verbose在提交日志里确认它读到的配置值;
第三,history server 启动时所在机器必须能访问 HDFS NameNode,否则写入日志会超时。我检查的时候发现是 HDFS 的安全模式下拒绝了写入,执行hdfs dfsadmin -safemode leave之后恢复正常。
5.6 端口冲突与防火墙问题
Spark 的默认端口比较多:8080 是 Master Web UI,7077 是 Master 通信端口,4040 是应用运行的临时端口,18080 是历史服务器端口。这些端口如果有别的服务占用了,启动的时候大概率直接报错。
排查端口占用:
netstat -tlnp | grep 8080 lsof -i :7077如果确实被占,要么改掉冲突服务的端口,要么修改 Spark 的配置。生产环境里通常不会关防火墙,而是把用到的端口加入白名单,这个按公司规范处理好就行,不建议为了环境省事去把节点的防护策略全部放开。
最后分享一点自己的实际体会
Spark 安装和配置这件事,说起来流程并不长,真正花时间的是理解每个参数背后对资源的影响。我在数仓项目里见过的绝大多数 Spark 运行问题,都不是 Spark 本身坏了,而是资源争抢、版本不匹配、配置不自洽这些环境层面的问题。
如果你也在搭建数仓运行环境,我建议多花几分钟把配置文件里的每一项都过一遍,尤其是SPARK_WORKER_MEMORY、spark.executor.memory、spark.eventLog.dir这三个。把它们理解透了,后面遇到性能问题和日志问题时,你的排查思路会清晰很多。
再分享一个实用的小技巧:每次改完配置,不用急着把 Spark 全部重启。如果是 spark-defaults.conf 的改动,重启 history server 就够;如果是 spark-env.sh 的改动,把 Master 和 Worker 都重启一遍,同时注意先通过jps确认旧进程真的退干净了再启动新的,避免遗留进程占用端口造成莫名的错乱。这个习惯能帮你避开好多奇奇怪怪的问题。