简介:《华为云大数据实验报告hhu》是一份面向高校大数据、云计算课程学习者的实验记录型文档,围绕华为云环境下ECS、OBS资源开通与集群部署展开,适合需要完成课程实验、复盘上机流程或准备大数据平台搭建练习的学生参考。压缩包内为1个docx文件,大小约4.36MB,内容以图文步骤和实验记录为主,便于按实验模块查阅。文档覆盖云主机实现大数据、云服务实现大数据、BigData Pro综合实验及大数据交互式查询四部分,涉及Hadoop集群搭建、节点SSH互通、OBS互联测试、Spark集群配置以及Spark SQL/Flink SQL查询分析等关键环节。已有2607人学习,可作为理解华为云大数据实验链路、整理报告结构与排查配置问题的实操参考资料。
1. 从四台云主机到一条跑通的 WordCount:这份大数据实验报告值不值
这份材料不是那种只有截图没有命令的课程作业。它把云上大数据实验拆成四条主线:弹性云服务器(ECS)手工搭 Hadoop 集群、对象存储与 HDFS 打通、Spark on YARN 部署、再加一个托管式大数据 Pro 服务的开箱体验,末尾接一段交互式查询。从采购云主机开始,一路走到hadoop jar ... wordcount输出结果,中间没有断点。
对只跑过单机伪分布式的读者,这份报告补的正是"多节点真集群"那一段:主机名怎么定、公钥怎么汇总、副本数在云盘上该设几、对象存储的凭证放哪。对已经在云上交付过环境的从业者,它的价值在另一头——托管服务和自建集群的边界在哪、哪些活该交给平台、哪些参数必须自己盯。
2. 节点规划与集群底座:ECS、hosts、免密互信三件套
云上搭集群的第一步永远是选型和组网,配错后面全白搭。常见翻车不是配置文件写错,而是机器买错、网络没通、主机名对不上。
2.1 为什么是四台同规格 ECS 而不是一台大机器
很多人第一次做这个实验会想:一台 16 核 64G 的机器开四个容器不就行了?省事。但 Hadoop 集群的意义在于跨物理节点验证分布式行为——数据块副本真的落在不同机器上、NodeManager 真的在不同主机上跑容器、某个节点挂了任务真的能重调度。单机多容器验证不了这些,只能在日志里自欺欺人。
节点规划我一般按下面这个思路走:
| 角色 | 建议节点 | 说明 |
|---|---|---|
| NameNode + ResourceManager | node1 | 主控,内存要给足,元数据全在它这 |
| DataNode + NodeManager | node1~node4 | 混布能省机器,实验环境够用 |
| SecondaryNameNode | node2 | 和 NameNode 分开,避免同机故障一起没 |
| Spark 客户端 / HistoryServer | node1 | 提交入口,端口要放行 |
数量上选 4 台而不是 3 台,是因为dfs.replication=3时如果只有 3 个 DataNode,任何一个节点维护都会导致副本不足进入安全模式。4 台留一个冗余位,容错演示才跑得下去。规格上 4C8G 起步、磁盘 40G 系统盘外加一块 100G 数据盘最舒服,因为 Hadoop 的dfs.datanode.data.dir和数据盘分开挂,重建节点时数据不受系统盘影响。
安全组放行是另一处容易被跳过的地方。内网互通靠 VPC,但跨网访问 NameNode Web UI(9870)、ResourceManager Web UI(8088)、HDFS RPC(8020)、YARN 的若干随机端口,都要在安全组里按需开。实验环境图省事会把内网段全放通,这个做法只适合临时实验,做完记得收。
提示:云上"关闭防火墙"和本地机房不是一回事。云主机内部
systemctl stop firewalld只关掉了操作系统层,真正拦流量的是安全组。两边都看,别只关一半。
2.2 主机名、hosts 与免密互信:一次配对,四次分发
Hadoop 的配置文件里到处是主机名,用 IP 写死以后扩容、迁移全要改。所以第一步是把主机名钉死,再让四台机器互相认得出对方。
# 四台 ECS 分别执行,把主机名固定下来,避免重启后回退成随机名 hostnamectl set-hostname node1 # node2 / node3 / node4 依次替换 # 四台机器统一写 hosts,IP 用控制台里的私有地址,不要用公网 IP cat >> /etc/hosts <<'EOF' 192.168.0.10 node1 192.168.0.53 node2 192.168.0.169 node3 192.168.0.77 node4 EOF # 验证:四台都能解析出同一个地址,才算过关 getent hosts node1 node2 node3 node4这段的关键是hosts必须四台完全一致,而且用私网地址。曾经踩过一个坑:某台机器漏写了 node3,NameNode 起来了,DataNode 也起来了,但hdfs dfsadmin -report里永远只有两个 Live 节点,日志里全是UnknownHostException。这种"看起来正常但少一半"的故障最耗时间。
接下来是免密。Hadoop 的启动脚本靠 SSH 分发命令,主节点必须能无密码跳到所有从节点。做法是每台生成密钥对,把四台的公钥汇总,再统一下发:
# 每台机器生成自己的密钥对,-N "" 表示不设口令,集群内部用必须为空 ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa # 关键一步:自己的公钥也要写进自己的 authorized_keys cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys # 在 node1 上汇总四台公钥,排序去重后形成一份统一的授权文件 for h in node1 node2 node3 node4; do ssh "$h" 'cat ~/.ssh/id_rsa.pub' done | sort -u > /tmp/all_pub # 用同一份文件覆盖四台的 authorized_keys,保证任意两台互通 for h in node1 node2 node3 node4; do scp /tmp/all_pub "$h":~/.ssh/authorized_keys ssh "$h" 'chmod 600 ~/.ssh/authorized_keys' done # 验收:BatchMode 下不能弹密码提示 for h in node1 node2 node3 node4; do ssh -o BatchMode=yes -o ConnectTimeout=5 "$h" 'hostname' done-b 4096是密钥长度,实验环境 2048 也够;-N ""表示私钥不加密,因为start-dfs.sh是非交互执行,带口令会卡在输入提示上。BatchMode=yes是验收的关键参数——加了这个,任何需要交互的路径都会直接失败而不是挂住,脚本化检查必加。
这种"汇总再分发"的做法只适合实验环境。生产环境用配置管理工具下发公钥,或者干脆走统一的身份认证中心,不要手工scp。
2.3 JDK 与系统参数:别在第一步埋雷
Hadoop 3.x 依赖 JDK 8 或 11,实验里 8 最稳。装完不要急着写JAVA_HOME,先确认路径——很多发行版which java指向的是/usr/bin/java这个软链,真正的目录在别处。
# 安装 OpenJDK,CentOS 系用 yum,Debian 系换 apt install openjdk-8-jdk yum install -y java-1.8.0-openjdk-devel # readlink -f 追到真实路径,写到 JAVA_HOME 里才不会指错 readlink -f "$(which java)" # 输出形如 /usr/lib/jvm/java-1.8.0-openjdk-.../bin/java # 追加到全局环境,四台都要做 cat >> /etc/profile.d/bigdata.sh <<'EOF' export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk export PATH=$JAVA_HOME/bin:$PATH EOF source /etc/profile.d/bigdata.shreadlink -f的输出要手工截掉末尾的/bin/java才是JAVA_HOME。这一步别偷懒用变量拼,容易多一层或少一层目录,最后HADOOP_HOME一跳转就报JAVA_HOME is not set,其实是设了但路径不对。
另外两项系统参数建议顺手改掉:vm.swappiness设为 1 减少换页,net.ipv6.conf.all.disable_ipv6关掉 IPv6 避免部分组件解析出::1。这些不影响集群起来,但影响跑起来之后稳不稳。
3. Hadoop 集群落地:五个配置文件决定成败
配 Hadoop 说白了就是把五个文件写对。写对了start-dfs.sh一把过,写错了看日志能耗一整天。这一章按文件顺序过一遍,每个文件只讲真正会卡人的参数。
3.1 core-site 与 hdfs-site:把 NameNode 地址和数据目录钉死
core-site.xml只干两件核心事:告诉所有节点 NameNode 在哪、临时目录放哪。
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>fs.defaultFS写成hdfs://node1:8020,不要写 IP,也不要省略端口。省略端口的情况下客户端会去猜,猜出来的结果和你实际启动的不一定一致。hadoop.tmp.dir是很多子目录的父目录,默认在/tmp下,系统重启就被清空,元数据跟着一起没——这是新手最容易吃的一次后悔药。指向数据盘,并提前mkdir -p建好。
hdfs-site.xml决定数据落在哪、存几份:
<configuration> <property> <name>dfs.namenode.name.dir</name> <value>/data/hadoop/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/data/hadoop/data</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.namenode.http-address</name> <value>node1:9870</value> </property> </configuration>dfs.replication在 4 节点实验环境里设 2 就够,设 3 会让每次格式化后的初始写入都等副本落齐,小文件测试会明显变慢。真实生产按机架数算,云上还要考虑不同可用区。dfs.namenode.http-address显式写出来,是为了避免 UI 端口在 9870 和老版本 50070 之间反复试探。
3.2 yarn-site、mapred-site 与 workers:计算资源怎么切
yarn-site.xml决定容器怎么分配。云主机内存有限,最容易出的事是 NodeManager 按默认值上报内存,YARN 直接判定可用资源不足,任务全卡在 ACCEPTED 状态。
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>node1</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>6144</value> </property> <property> <name>yarn.nodemanager.resource.cpu-vcores</name> <value>4</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>4096</value> </property> </configuration>yarn.nodemanager.resource.memory-mb是每个 NodeManager 愿意交出来的内存总量,不是机器总内存。8G 机器留 2G 给系统和 DataNode,写 6144 比较稳。maximum-allocation-mb是单个容器上限,比它大一定小于等于前面那个总量。这两个值设反了(比如单容器上限大于节点总量),任务会直接报InvalidResourceRequestException,报错信息还不太直观。
mapred-site.xml把 MapReduce 的执行引擎指到 YARN:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>yarn.app.mapreduce.am.env</name> <value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value> </property> <property> <name>mapreduce.map.env</name> <value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value> </property> <property> <name>mapreduce.reduce.env</name> <value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value> </property> </configuration>后三个env参数是 Hadoop 3 上最容易漏的一组。漏了的典型现象是:作业提交成功,AM 容器也起来了,然后立刻Error: Could not find or load main class或者Container exited with a non-zero exit code 1。原因是 NodeManager 在别的机器上拉起容器,那边不知道 MapReduce 的 jar 在哪,必须通过环境变量传过去。
workers(老版本叫slaves)文件决定start-dfs.sh会去哪些机器启进程:
# $HADOOP_HOME/etc/hadoop/workers,一行一个主机名,不要写 IP node1 node2 node3 node4主节点也写进去,因为混布模式下 node1 同样跑 DataNode 和 NodeManager。漏写主节点会出现"节点数总是比机器数少一"的玄学现象。
3.3 格式化、启动与 WordCount 验收
配置写完,剩下的动作就三个:格式化、启动、验。
# 第一次启动前格式化,只执行一次 hdfs namenode -format # 启动 HDFS 和 YARN,脚本会按 workers 文件逐台 ssh 过去启进程 start-dfs.sh start-yarn.sh # 四台分别核对,node1 应有 NameNode/ResourceManager,其余有 DataNode/NodeManager jpshdfs namenode -format是单向操作,重复执行会让 NameNode 生成新的 clusterID,而老 DataNode 的数据目录里还是旧 ID,结果就是 DataNode 全起但一个都注册不上。看到hdfs dfsadmin -report里Live datanodes (0),先想想是不是手抖又格式化了一次。真发生了,要么清空所有 DataNode 的数据目录重来,要么按 clusterID 手工对齐,前者更省事。
# 造一份小数据,跑官方示例验证整条链路 hdfs dfs -mkdir -p /input echo "cloud big data cloud hadoop yarn spark cloud" > /tmp/a.txt hdfs dfs -put /tmp/a.txt /input/ hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar \ wordcount /input /output # 输出目录必须事先不存在,存在会直接报错退出,这是设计如此 hdfs dfs -cat /output/part-r-00000hadoop jar后面那个版本号要跟着实际安装包改,写死版本号是个常见疏忽。wordcount的输出目录不能预先存在,重跑前记得hdfs dfs -rm -r /output。这条命令跑通、part-r-00000里能按词频倒出结果,说明 NameNode、DataNode、ResourceManager、NodeManager、Shuffle 全部链路是活的,比看多少个"运行成功"的截图都实在。
4. 打通对象存储:HDFS 之外的第二份数据底座
HDFS 适合热数据和高吞吐顺序读,但云上集群一旦释放,数据跟着没。对象存储按量计费、容量近乎无上限、生命周期策略齐全,天然适合放冷数据和跨集群共享的输入集。这一章把对象存储接进 HDFS 视图,再把 Spark 拉起来做交互式查询。
4.1 选型理由:什么数据该放对象存储
一个常见的判断标准:需要频繁被 MapReduce/Spark 直接扫描、且要求低延迟的中间结果,放 HDFS;原始输入集、备份、跨团队共享的样本、以及生命周期超过集群寿命的数据,放对象存储。
代价是延迟。对象存储走 HTTP,单次ls的耗时比 HDFS 高一个量级,小文件多了会非常难受。所以接入的正确姿势是"大批量读写走 distcp,不要拿它当 HDFS 用"。另一个好处是解耦:计算集群可以随时销毁重建,数据留在桶里,重建后挂上就能继续跑,这在做周期性实验时省下大量重复采购和上传的时间。
4.2 适配包、AK/SK 与 endpoint 配置
Hadoop 原生不认识对象存储协议,需要云厂商提供的 Hadoop 适配包(通常叫 OBSA 或 hadoop-obs 一类),把对应的 jar 放进$HADOOP_HOME/share/hadoop/common/lib/,四台都要放。然后配置访问凭证:
<!-- core-site.xml 追加,凭证建议用占位符,不要直接提交到代码仓库 --> <configuration> <property> <name>fs.obs.endpoint</name> <value>obs.<region>.example-cloud.com</value> </property> <property> <name>fs.obs.access.key</name> <value>${env.OBS_AK}</value> </property> <property> <name>fs.obs.secret.key</name> <value>${env.OBS_SK}</value> </property> </configuration>三个参数的坑点各不相同。endpoint必须和桶所在区域一致,跨区写会报签名不匹配,而且报错信息通常只给一个 403,看不出是区域问题。凭证用环境变量引用${env.OBS_AK}而不是硬编码,是因为配置文件会被打进镜像、被复制到所有节点、被贴进实验报告——原始材料里就有把密钥明文写在文档里的做法,这在真实环境里是必须立刻轮换的事故。
# 先把 AK/SK 写进当前 shell 环境,再启动客户端进程 export OBS_AK="<your-access-key>" export OBS_SK="<your-secret-key>" # 验证连通性:能列出桶根目录说明凭证和 endpoint 都对 hadoop fs -ls obs://bucket-demo/ # 把 HDFS 里的数据推到桶里,distcp 是并行拷贝,比 get/put 循环快得多 hadoop distcp /input/a.txt obs://bucket-demo/raw/ # 反向读回来,确认双向都通 hadoop fs -cat obs://bucket-demo/raw/a.txtdistcp的并行度由-m控制,默认值偏保守,文件多时加-m 16明显提速。但注意别开太大,对象存储对并发连接数有配额,超了会返回 503,表现是拷贝到一半大量重试。凭证的时效性也要留心:临时凭证(STS)有过期时间,跑长作业时中途失效,报错是RequestTimeTooSkewed或签名过期,看起来很莫名,其实是时钟或有效期问题。
4.3 Spark on YARN 的两个必改参数
Spark 装起来简单,解压改两个文件就行,难点在让它和 YARN、HDFS、对象存储三边都对上。
# 解压到统一目录,四台保持路径一致,YARN 分发依赖时靠这个路径 tar -zxvf spark-3.5.1-bin-hadoop3.tgz -C /opt mv /opt/spark-3.5.1-bin-hadoop3 /opt/spark # 从模板复制配置,直接改模板文件会导致升级时被覆盖 cp /opt/spark/conf/spark-defaults.conf.template /opt/spark/conf/spark-defaults.confspark-defaults.conf里真正会卡人的是这几行:
# 提交到 YARN,不要用 standalone,实验环境没必要多维护一套 Master spark.master yarn spark.submit.deployMode client # 事件日志写 HDFS,否则 HistoryServer 重启后历史全丢 spark.eventLog.enabled true spark.eventLog.dir hdfs://node1:8020/spark-events spark.yarn.historyServer.address node1:18080 spark.history.fs.logDirectory hdfs://node1:8020/spark-events # 对象存储凭证要从 Spark 侧透传给 Hadoop,只配 core-site 有时候不生效 spark.hadoop.fs.obs.endpoint obs.<region>.example-cloud.com spark.hadoop.fs.obs.access.key <your-access-key> spark.hadoop.fs.obs.secret.key <your-secret-key>spark.eventLog.dir指向的 HDFS 目录要事先建好并给权限,否则 HistoryServer 起来是空页面。spark.hadoop.*前缀是把 Hadoop 配置项注入 Spark 运行时的标准做法,很多人只在core-site.xml里配了对象存储,结果spark-submit里读obs://路径还是失败,就是因为 executor 侧的环境没有继承到。
# 用官方示例验一次,client 模式下 driver 在本机,日志直接可见 $SPARK_HOME/bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn \ --deploy-mode client \ --executor-memory 1g \ --executor-cores 1 \ --num-executors 2 \ $SPARK_HOME/examples/jars/spark-examples_2.12-3.5.1.jar 100--num-executors 2是刻意的保守值,4 台 8G 的机器上开太多 executor 会互相抢内存,任务反而更慢。调参时先看 YARN 的yarn node -list剩余可用内存,再决定 executor 数量和单实例内存,别照抄网上的大集群参数。
4.4 Spark SQL 跑通第一条交互式查询
批处理验证完,交互式查询是这套实验里最像"真实业务"的一段。用 Spark SQL 建库建表、灌几行数据、跑一个聚合,链路就闭环了。
-- 进入 spark-sql 后执行,元数据默认落 Derby,想多会话共享要换成 Hive Metastore CREATE DATABASE IF NOT EXISTS demo; USE demo; CREATE TABLE IF NOT EXISTS access_log ( dt STRING, uri STRING, pv BIGINT ) STORED AS PARQUET; INSERT INTO access_log VALUES ('2024-05-01', '/index', 1200), ('2024-05-01', '/detail', 860), ('2024-05-02', '/index', 1310); -- 交互式聚合,验证 SQL 引擎和存储格式都正常 SELECT dt, SUM(pv) AS total FROM access_log GROUP BY dt ORDER BY dt;STORED AS PARQUET是刻意选的,列式存储对聚合查询友好,也顺带验证了 Spark 的写路径。默认的 Derby 元数据库是单会话独占的,第二个spark-sql进程连不上会报Another instance of Derby may have already booted——这不是错,是设计。想让多个入口共享表定义,得把hive.metastore.uris指到一个独立起的 Metastore 服务上,这也是从"能跑 demo"到"能多人协作"的分水岭。
5. 翻车现场复盘:五处最容易被忽略的配置与凭证问题
云上集群的问题有个共同特征:报错信息指向的地方,往往不是真正出错的地方。这一章挑五处高频翻车点,按现象、原因、解决拆开写。
5.1 免密只做了单向,从节点启动全失败
现象:start-dfs.sh在 node1 上执行,输出里一路Permission denied (publickey),但手工ssh node2又是通的。
原因:手工连的时候走的是交互式认证,可能命中了缓存的 agent 或者你之前在别的会话里输入过密码;而启动脚本用的是BatchMode,任何非密钥路径都会失败。另一种情况是只做了 node1 到从节点的单向信任,从节点回连主节点时没权限。
解决:用ssh -o BatchMode=yes node2 hostname逐台验证,四台两两互通都要过。不通过就回到汇总分发那一步,确认authorized_keys里确实包含所有四台的公钥,且权限是 600、目录是 700。权限过宽 SSH 会静默拒绝,日志里只有一句Authentication refused: bad ownership or modes。
5.2 主机名对不上,DataNode 起来了但注册不上
现象:jps显示 DataNode 进程在,但hdfs dfsadmin -report里 Live 节点数始终少于机器数,NameNode 日志里刷java.net.UnknownHostException。
原因:/etc/hosts四台不一致,或者改了hostnamectl之后没重新登录导致hostname命令返回的还是旧名。也有一种是同时存在 IPv6 解析,客户端拿到了::1去连。
解决:四台跑同一句getent hosts node1比对输出,必须完全一致。改完 hosts 后重启相关进程,别指望热生效。如果环境里有 IPv6,在/etc/sysctl.conf里关掉,或者确保 hosts 里同一主机名只对应一条 IPv4 记录。
5.3 重复格式化,集群一夜回到解放前
现象:改了个小配置想重启,顺手又跑了一次hdfs namenode -format,之后 DataNode 全在但一个都不注册,日志报 clusterID 不一致。
原因:格式化会为 NameNode 生成全新的 clusterID,而 DataNode 的VERSION文件里还是旧的,两边对不上就直接拒绝。
解决:清空所有节点dfs.datanode.data.dir指向的目录和 NameNode 的name目录,重新格式化一次,然后一次启动到位。这件事没有优雅的后悔药,只能重来。养成习惯:-format只在新集群第一次启动时执行,之后任何改动都不碰它。
5.4 密钥泄露与凭证过期,两种完全不同的报错
现象一:配置文件里明文写了 AK/SK,后来被贴进文档或提交进仓库,只能整对轮换。 现象二:作业跑到一半开始大量失败,报RequestTimeTooSkewed或 403。
原因:前者是凭证管理缺失;后者要么是机器时钟偏移超过允许窗口(对象存储签名对时间敏感,通常容忍 15 分钟),要么是用了临时凭证且已过期。
解决:AK/SK 一律走环境变量或密钥管理服务,配置文件里只留占位符。四台机器统一配 NTP 时间同步,chronyc tracking看偏移量,超过几百毫秒就要处理。临时凭证的场景下,把有效期覆盖住整个作业时长,长作业提前续期。
5.5 YARN 资源参数设反,任务全卡在 ACCEPTED
现象:spark-submit或hadoop jar提交后,YARN UI 上任务一直 ACCEPTED,日志里没有报错,就是不动。
原因:yarn.scheduler.maximum-allocation-mb设得比yarn.nodemanager.resource.memory-mb还大,或者申请的单容器内存超过了节点能提供的上限。调度器找不到任何能满足的节点,于是无限等待。
解决:先看yarn node -list里每台节点的可用内存和 vCore,再倒推能申请多少。规则记住一条:单容器上限 ≤ 节点总量 ≤ 物理内存减去系统预留。改完配置重启 ResourceManager 和 NodeManager,光 reload 有的版本不生效。
6. 交付前的十五分钟自检:把"看起来跑起来了"变成可复现
这套实验最尴尬的场景不是跑不起来,是演示当天在别人机器上跑不起来。我后来形成一个习惯:任何一套集群环境交付前,先跑一遍开机自检脚本,把"我以为它是好的"变成"我知道它哪几项是好的"。
#!/usr/bin/env bash # cluster-smoke.sh —— 交付前跑一遍,任一项 FAIL 就先别往下演示 set -u FAIL=0 check() { if eval "$2" >/dev/null 2>&1; then echo "OK $1" else echo "FAIL $1" FAIL=1 fi } check "JDK 可用" "java -version" check "主机名可解析" "getent hosts node1" check "node2 免密通过" "ssh -o BatchMode=yes -o ConnectTimeout=5 node2 true" check "NameNode 存活" "hdfs dfsadmin -report" check "YARN 节点在线" "yarn node -list" check "对象存储可读" "hadoop fs -ls obs://bucket-demo/" check "Spark 可提交" "spark-submit --version" exit $FAILset -u让未定义变量直接报错,避免拼写错误被静默吞掉;check函数把每条命令的退出码转成 OK/FAIL,退出码汇总到FAIL变量,最后exit $FAIL让脚本在 CI 或流水线里也能用。这段二十来行的脚本,比任何一份写得漂亮的文档都管用。
配套的验收标准我一般列成一张表,逐项对:
| 验收项 | 期望结果 | 失败先看哪 |
|---|---|---|
| Live DataNode 数 | 等于 workers 文件行数 | /etc/hosts、clusterID、安全组 |
| YARN 可用内存 | 接近节点物理内存的 75% | yarn-site.xml两个内存参数 |
| WordCount 输出 | part-r-00000有按词频排序的结果 | mapred-site.xml的三个 env |
| 对象存储读写 | ls与cat都通 | endpoint 区域、AK/SK、时钟偏移 |
| Spark on YARN | 任务状态从 ACCEPTED 走到 FINISHED | executor 内存申请是否超上限 |
| SQL 聚合 | 返回行数与输入一致 | Derby 独占、表路径权限 |
有一次我把这套脚本交给别人复现,对方在第三项就 FAIL 了,原因是他在新机器上重新生成了密钥对但没重新分发,authorized_keys里还是旧公钥。这件事之后,我每次交付前都强制走一遍自检,尤其是免密这一项——它不是配置问题,是环境状态问题,换个机器就归零。希望这份拆解能帮你少走一遍我走过的弯路。
本文还有配套的精品资源,点击获取