ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

四台云主机+对象存储桶:Hadoop/Spark实验链路复现与避坑

四台云主机+对象存储桶:Hadoop/Spark实验链路复现与避坑

简介:《华为云大数据实验报告hhu》是一份面向高校大数据课程学习者与云计算入门实践者的实验指导文档,围绕在华为云上搭建与管理大数据平台展开,帮助读者打通从云主机、对象存储到集群部署与查询分析的完整链路。压缩包共1个文件,为4.36MB的docx文档,按实验模块编排,便于按目录检索与对照操作。内容覆盖实验一云主机实现大数据中的ECS与OBS配置、访问密钥设置及Hadoop集群搭建,实验二的云服务大数据实践,综合实验一BigData Pro中Hadoop与Spark集群的部署验证,以及综合实验四基于Spark SQL或Flink SQL的交互式查询。读者可从中获得节点通信、集群测试、与OBS互联、环境配置与查询分析等具体操作记录和排错参考。目前已有2541人学习,适合课程实验、上机实训与云平台入门自学者使用。

1. 四台云主机加一个对象存储桶,把四个大数据实验串成一条可复现的链路

拿到这份资源的人,多半是在赶一个「云上大数据」的课程实验:要在大数据实验报告里同时交代清楚云主机怎么开、Hadoop 集群怎么搭、对象存储怎么接、Spark 怎么跑查询。单看每个环节都不难,难的是四件事连起来之后的衔接处——节点互信没做全、NameNode 格式化了两遍、OBS 的 jar 没进 classpath、YARN 容器被内存掐死,任何一处卡住,后面全是白干。这份资源的价值不在「讲大数据是什么」,而在于它留下了一条从买 ECS、建 OBS 桶、配 hosts、做免密、装 JDK 到跑通 wordcount 和 Spark SQL 的完整命令链和配置片段,你可以照着抄,也可以拿它当排错时的对照物。适合两类人:一类是要在一两天内把实验环境和报告一起交出去的学生,另一类是想在云上搭一套最小可用 Hadoop/Spark 集群、又不想从零翻官方文档的工程师。

先说一句可能不太中听的:这份报告原文里贴了明文的访问密钥、完整的公钥和四台机器的内网 IP。这些对复现没有任何帮助,反而属于典型的血泪教训式泄露。你拿到手第一件事应该是把它们打码,第二件事是去控制台把对应的密钥删掉重发一对。下面的内容会把所有凭据换成占位符,配置项一个不少,密钥一个不写。

2. 节点规划与系统基线:hosts、免密、防火墙这三件事必须先做对

集群搭建里 80% 的「玄学问题」都出在正式装 Hadoop 之前的那半小时。很多人打开四台机器就开始解压安装包,结果 DataNode 起不来、SSH 还要输密码、Web UI 打不开,回头一个个排查,时间全耗在这。我一般的顺序是:规划角色 → 定主机名 → 写 hosts → 做全互联免密 → 关防火墙并对时。这五步做完再碰 Hadoop,后面会顺很多。

2.1 为什么是四节点而不是一台全装

一台机器上把 NameNode、DataNode、ResourceManager、NodeManager 全塞进去,技术上能跑,但你会失去两个关键观察点:一是副本因子没法真实生效,dfs.replication 设成 3 也只是一份数据;二是 YARN 的资源调度看不出来,容器分配、队列、节点黑名单这些行为全被掩盖。四台(1 主 3 从)是成本最低的「能看到分布式行为」的配置,也是多数实验报告要求的最小拓扑。

角色主机名建议规格进程
Masternode14 vCPU / 8 GB / 系统盘 40 GBNameNode、SecondaryNameNode、ResourceManager
Workernode24 vCPU / 8 GB / 系统盘 40 GBDataNode、NodeManager
Workernode34 vCPU / 8 GB / 系统盘 40 GBDataNode、NodeManager
Workernode44 vCPU / 8 GB / 系统盘 40 GBDataNode、NodeManager

四台机器务必放在同一个 VPC、同一个子网、同一个安全组里,走内网通信。这一点不是建议是硬要求:如果节点之间用公网 IP 互相注册,DataNode 上报给 NameNode 的地址会是公网地址,跨节点传数据会绕出去再绕回来,轻则慢到无法接受,重则因为安全组规则不匹配直接连不上。买机器的时候顺手把内网 IP 记下来,后面 hosts 只写内网地址。

2.2 主机名与 /etc/hosts:别让 Hadoop 去猜

每台机器先设主机名,再写统一的 hosts。四台机器的 /etc/hosts 内容必须完全一致,否则某个节点解析不到别人,表现就是「能 ping 通 IP、ping 不通主机名」。改完主机名要重新登录一次 shell,否则提示符还是旧的。

# 在各自节点上执行,node1~node4 按角色替换 hostnamectl set-hostname node1 # 四台机器都要写,内容完全相同;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 # 逐个验证,四台机器上都要能解析出正确地址 for h in node1 node2 node3 node4; do ping -c1 $h >/dev/null && echo "$h ok"; done

这里的 192.168.0.x 是内网网段示例,实际以控制台里每台机器的私网地址为准。注意不要写成 127.0.0.1 或者公网地址。另外有些镜像自带 cloud-init 生成的 hostname 映射,会把 node1 指向 127.0.0.1,那种情况下你的追加行要放在文件靠前的位置,或者直接把自带的那行删掉,否则 Hadoop 会连到自己身上。

2.3 全互联免密:为什么不能只做单向

Hadoop 的启动脚本有个容易被忽略的行为:在 node1 上执行 start-dfs.sh,它会通过 SSH 到各个 worker 上拉起 DataNode,而 SecondaryNameNode 又可能需要反向连回。只做 node1 → node2/3/4 的单向免密,某些版本能启动,但一旦涉及 distcp、跨节点脚本分发就会卡在密码提示上。既然四台机器都要互信,那就一次做全。

常见做法是每台机器生成密钥,把所有公钥汇总成一个 authorized_keys 再分发回去,而不是挨个执行 ssh-copy-id 做 12 次。

# 四台机器分别执行,一路回车,不要设密码短语 ssh-keygen -t rsa -b 2048 -N '' -f /root/.ssh/id_rsa # 每台机器执行,把本机公钥临时汇总到 node1 ssh node1 "mkdir -p /root/.ssh/keys" # 在 node1 上收集(如果 node1 到其他节点此时还没免密,就手工拷贝文件) cat /root/.ssh/id_rsa.pub >> /root/.ssh/keys/all.pub # node1 上把汇总文件分发到四台机器的 authorized_keys for h in node1 node2 node3 node4; do scp /root/.ssh/keys/all.pub $h:/root/.ssh/authorized_keys ssh $h "chmod 700 /root/.ssh && chmod 600 /root/.ssh/authorized_keys" done # 验证:四台机器交叉 ssh,做到完全不提示密码 ssh node1 "for h in node1 node2 node3 node4; do ssh -o BatchMode=yes $h hostname; done"

参数含义里最要紧的是-N ''(空密码短语)和最后的chmod 600。权限是免密失败的头号原因:SSH 对 authorized_keys 和 .ssh 目录的权限极其挑剔,755 或 644 都会被拒绝,而且日志只给你一句Permission denied (publickey),不说为什么。BatchMode=yes的作用是强制非交互,一旦需要密码就直接失败,比手工测试可靠得多——否则脚本会静静地卡在密码提示那里,你以为跑完了。

2.4 防火墙、安全组与时间同步

实验环境里最常见的处理是直接关掉 firewalld 和 SELinux,省得跟端口较劲。但云上还有一层安全组,关掉系统防火墙不等于端口放通,这点经常被漏掉。NameNode 的 9000、YARN 的 8088、HDFS Web 的 9870、Spark 的 8080,这几台机器之间要互通,安全组里加一条「同安全组内全部放行」最省事。

# 四台机器都执行 systemctl stop firewalld && systemctl disable firewalld setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config # 时间同步,集群节点时间差过大会导致 Kerberos、日志排查全乱 yum install -y chrony && systemctl enable --now chronyd chronyc sources -v

SELinux 那条 sed 改的是配置文件,setenforce 0只对当前生效,重启后会按配置文件来,两条要一起做。chrony 装完用chronyc sources看一眼有没有^*标记的同步源,如果全是?说明出网受限,实验环境里影响不大,但排查日志时心里要有数:时间戳对不齐的时候,别急着怀疑代码。

3. Hadoop 集群搭建:从 JDK 到 wordcount 出结果

到这里四台机器已经是「互相认识、互相能免密登录、端口全通」的状态了,剩下的就是把软件铺上去、配置写对、启动验证。这一章按执行顺序走,每一步之后都给了「应该看到什么」,对照不上就停下来查,别硬着头皮往下装——带着错误的 NameNode 去格式化,后面只会更乱。

3.1 JDK 与目录约定

Hadoop 对 JDK 版本敏感,生产上常见的组合是 JDK 8 配 Hadoop 3.x,实验环境用发行版自带的 OpenJDK 8 就够。安装位置统一到 /opt,四台机器路径必须一致,否则后面环境变量一改就出岔子。

# 四台机器执行 yum install -y java-1.8.0-openjdk-devel java -version # 应输出 1.8.0_xxx # 统一软件目录 mkdir -p /opt/bigdata && cd /opt/bigdata # Hadoop 安装包用 wget 从镜像站拉,或者本地上传,注意选带 hadoop 前缀的 tar.gz tar -xzf hadoop-3.x.x.tar.gz -C /opt/bigdata ln -s /opt/bigdata/hadoop-3.x.x /opt/bigdata/hadoop # 环境变量,四台机器保持一致 cat > /etc/profile.d/bigdata.sh <<'EOF' export JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk export HADOOP_HOME=/opt/bigdata/hadoop export SPARK_HOME=/opt/bigdata/spark export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$SPARK_HOME/bin export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop EOF source /etc/profile.d/bigdata.sh

JAVA_HOME一定要用readlink -f $(which java)反查真实路径后再填,/usr/lib/jvm/jre-1.8.0-openjdk在很多发行版上是个软链,而 Hadoop 的启动脚本对软链的容忍度不高,会报JAVA_HOME is not set。我一般直接readlink -f /usr/bin/java | sed 's:/bin/java::'拿到绝对路径写进去。HADOOP_CONF_DIR 这个变量是为 Spark 准备的,Spark 找 Hadoop 配置就是靠它,现在设好,后面能省一次排查。

3.2 四个 XML 配置逐项拆

配置目录是$HADOOP_HOME/etc/hadoop。四个文件里,core 定全局默认文件系统,hdfs 定副本和存储路径,yarn 定资源调度,mapred 定计算框架。每改一个文件都要四台同步,我习惯在 node1 上改完统一 scp 分发。

<!-- core-site.xml --> <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://node1:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/bigdata/data/tmp</value> </property> <property> <name>fs.trash.interval</name> <value>1440</value> </property> </configuration>

fs.defaultFS写的是逻辑名 + 端口,用主机名而不是 IP,这样将来迁移节点只改 hosts。9000 是 NameNode 的 RPC 端口,被占用了就换 8020,改完记得同步到所有客户端配置。hadoop.tmp.dir千万别留在 /tmp 下,系统重启或定时清理任务会把它删掉,表现是集群莫名其妙起不来、元数据全丢,这个坑我踩过不止一次。

<!-- hdfs-site.xml --> <configuration> <property> <name>dfs.replication</name> <value>3</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///opt/bigdata/data/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///opt/bigdata/data/dfs/data</value> </property> <property> <name>dfs.namenode.secondary.http-address</name> <value>node1:9868</value> </property> </configuration>

副本数 3 对应三台 worker,正好一个不浪费。file:///前缀不能省,省了 Hadoop 会按默认文件系统去解析这个路径,结果路径跑到 HDFS 上去了,报错信息还很绕。三个 worker 的 data.dir 是本地盘路径,四台机器上都要提前 mkdir 好目录,权限给 root。

<!-- yarn-site.xml --> <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>node1</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>6144</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>6144</value> </property> <property> <name>yarn.nodemanager.env-whitelist</name> <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value> </property> </configuration>

内存这两个参数是 8 GB 机器的经验值:给 NodeManager 留 6 GB,剩下的留给系统和 DataNode。env-whitelist是 Hadoop 3.x 之后必须显式配的,不配会出现容器里找不到 JAVA_HOME、任务一启动就失败,日志里只有一句Container exited with a non-zero exit code 1,非常不友好。

<!-- mapred-site.xml --> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>yarn.app.mapreduce.am.env</name> <value>HADOOP_MAPRED_HOME=/opt/bigdata/hadoop</value> </property> <property> <name>mapreduce.map.env</name> <value>HADOOP_MAPRED_HOME=/opt/bigdata/hadoop</value> </property> <property> <name>mapreduce.reduce.env</name> <value>HADOOP_MAPRED_HOME=/opt/bigdata/hadoop</value> </property> </configuration>

框架设成 yarn 之后,那三条 env 必须补上,否则任务容器里找不到 mapreduce 的 jar 包。这一条在很多老教程里没有,因为 Hadoop 2.x 时期有默认值兜底,换到 3.x 就翻车。

还有一个容易被版本差异坑到的点:worker 列表文件在 Hadoop 2.x 叫slaves,3.x 叫workers。里面一行一个主机名,node1 通常不写进去(它是 master,不跑 DataNode),写 node2/3/4 三行即可。

3.3 格式化只能做一次

# 仅在 node1 上执行,且只执行一次 hdfs namenode -format # 启动 HDFS,脚本会自动 ssh 到各 worker 拉起 DataNode start-dfs.sh # 启动 YARN start-yarn.sh # 验证 jps hdfs dfsadmin -report

jps在 node1 上应该看到 NameNode、SecondaryNameNode、ResourceManager 三个进程,node2~4 上应该看到 DataNode、NodeManager 两个。少一个就去看对应节点的日志,路径在$HADOOP_HOME/logs/,文件名后缀是进程名,先看最后 50 行。

hdfs dfsadmin -report是比 jps 更硬的证据,它会列出 Live datanodes 的数量和每台的容量。数量是 3、状态是 In Service,才算集群真的组起来了。如果显示 0,或者报告里有 Dead datanodes,回去查 hosts 解析和防火墙,别在别处浪费时间。

关于格式化,必须强调:hdfs namenode -format会生成一个新的 clusterID 并清空 name 目录。第二次执行后,三个 DataNode 上存的还是旧 clusterID 的数据块,握手时对不上,表现是 DataNode 起来几秒后自动退出,日志里写Incompatible clusterIDs。解决办法只有两个:要么删掉所有节点上的 data 目录重新格式化,要么手工把 clusterID 对齐。所以我一般格式化前先ls /opt/bigdata/data/dfs/name确认目录是空的,格式化后立刻hdfs dfsadmin -report记录下来,后面出问题第一时间知道是不是又格式化了。

3.4 wordcount 跑通与结果解读

# 造一份输入数据 hdfs dfs -mkdir -p /input/wordcount echo -e "hadoop spark hdfs\nspark yarn hdfs\nhdfs namenode" > /tmp/words.txt hdfs dfs -put /tmp/words.txt /input/wordcount/ # 跑自带的 wordcount 示例 hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar \ wordcount /input/wordcount /output/wc1 # 看结果 hdfs dfs -cat /output/wc1/part-r-00000

输出目录必须不存在,Hadoop 不会覆盖已有路径,这是防误删的设计,报FileAlreadyExistsException时换个目录名就行,别去 rm -r 生产路径。part-r-00000里的r表示 reduce 阶段的输出,如果只看到part-m-00000说明 reduce 数是 0,检查输入是不是太小或者配置里mapreduce.job.reduces被设成了 0。

跑通之后去 8088 端口看 YARN 的任务页面,能看到这个 application 的 Map 和 Reduce 各几个、各在哪个节点上跑、耗时多少。这一步比看输出文件更有价值:它是「集群真的在协同工作」的最直接证据,也是实验报告里最有说服力的一张截图。

4. OBS 对接:AK/SK、并行文件系统与一次连通性验证

HDFS 解决的问题是「集群内怎么存」,对象存储解决的是「集群外怎么喂数据和怎么长期留」。把两者接上,才能做「数据放对象存储、计算在集群里跑」这种真实场景。这一章的重点不在创建桶的按钮在哪,而在配置项的语义和那几个必然会踩的坑。

4.1 对象存储和 HDFS 的边界先划清

两者不是替代关系。HDFS 是块存储思路,适合顺序读写大文件、支持追加和多副本本地化计算;对象存储是扁平命名空间,容量近乎无限、按量计费、支持 HTTP 直读,但 rename 操作在底层是 copy + delete,小文件多的时候性能会掉得很厉害,也不支持随机写。

所以合理的用法是:原始数据、历史归档、Spark 读取的大宽表放对象存储;中间结果、shuffle 数据、需要频繁重命名的临时目录放 HDFS。我见过有人把 shuffle 目录配到对象存储上,任务跑了四十分钟没出结果,查下来全是 rename 卡住——这不是配置错,是选型错。

实际配置里还有一个概念要分清:普通对象桶和并行文件系统。前者走 S3 风格接口,适合 Spark/Hive 直接读;后者是挂载成 POSIX 文件系统用,适合需要文件语义的场景。做 Hadoop 对接实验,用前者配fs.obs.impl更直接,用后者就要走 obsfs 挂载,多一层依赖。

4.2 建桶、拿密钥、配访问方式

控制台上建桶的时候,区域要选得和 ECS 一致,跨区域的访问延迟和流量费用都很难看。桶名全局唯一,建完把 endpoint 抄下来,形如obs.<region>.xxx.com,注意这里要用不带桶名的那条。

访问密钥从控制台的「我的凭证」里创建,下载下来的 csv 里包含 Access Key Id 和 Secret Access Key,Secret 只显示一次,丢了只能删了重建。这份 csv 绝对不能进 git、不能贴进实验报告、不能截图发群里。同一对密钥可以用「临时凭证 + 委托」的方式下发给程序,但那属于进阶用法,实验环境里直接把密钥写进配置文件也行,前提是机器只有你自己用。稳妥一点的做法是用环境变量注入,至少别落到提交物里。

4.3 让 Hadoop 认识 obs:// 这个 scheme

Hadoop 默认只认 hdfs、file 这几种 scheme,看到obs://会直接抛No FileSystem for scheme "obs"。要让它认识,需要两样东西:对接 jar 包和 fs.obs.* 系列配置。

# 1) 把对象存储的 hadoop 对接 jar(含依赖)放到公共 classpath # 注意 Hadoop 3.x 用 share/hadoop/tools/lib,部分版本用 common/lib,两个都放一份最稳 cp obs-hadoop-*.jar $HADOOP_HOME/share/hadoop/tools/lib/ cp obs-hadoop-*.jar $HADOOP_HOME/share/hadoop/common/lib/ # 2) 同步到四台机器 for h in node2 node3 node4; do scp $HADOOP_HOME/share/hadoop/tools/lib/obs-hadoop-*.jar \ $h:$HADOOP_HOME/share/hadoop/tools/lib/ done

jar 包版本必须和 Hadoop 大版本对齐,2.x 的包丢进 3.x 会在类加载阶段就报NoSuchMethodError,那种报错信息指向的类名和实际问题毫无关系,非常费时间。放完 jar 要重启 HDFS 和 YARN,因为 classpath 是在 JVM 启动时确定的。

<!-- core-site.xml 追加 --> <property> <name>fs.obs.impl</name> <value>org.apache.hadoop.fs.obs.OBSFileSystem</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> <property> <name>fs.obs.endpoint</name> <value>obs.<region>.xxx.com</value> </property> <property> <name>fs.obs.buffer.dir</name> <value>/opt/bigdata/data/obs-buffer</value> </property>

fs.obs.impl是 scheme 到实现类的映射,写错了不会报错,只会在真正访问 obs:// 时才失败。AK/SK 这里用了${env.OBS_AK}的写法,Hadoop 支持从环境变量取值,这样配置文件本身可以进版本库而密钥不进。注意环境变量要在启动脚本能读到的位置设置,比如写进/etc/profile.d/bigdata.sh后重新登录,否则守护进程读不到。buffer.dir是上传大文件时的本地暂存目录,空间要比单个最大文件大一些,默认值在 /tmp 下,同样有被清理的风险。

4.4 连通性测试与一次 Spark SQL 交互式查询

验证分两层:先看能不能列目录,再看能不能读数据算结果。第一层不通就别写 SQL。

# 第一层:列桶、传文件、读回来 hadoop fs -ls obs://your-bucket/ echo "hello obs" > /tmp/t.txt hadoop fs -put /tmp/t.txt obs://your-bucket/demo/ hadoop fs -cat obs://your-bucket/demo/t.txt # 第二层:把 HDFS 上的结果直接拷到对象存储 hadoop distcp /output/wc1 obs://your-bucket/output/wc1

distcp是跨文件系统的标准搬运工具,比hdfs dfs -cp靠谱得多,后者在跨 scheme 时偶发权限和并发问题。跑完去控制台的对象列表里确认文件真的在,别只信命令行的返回码。

交互式查询这一层,用 Spark SQL 直接读对象存储上的数据最省事:

-- 启动:spark-sql --master yarn --deploy-mode client CREATE EXTERNAL TABLE IF NOT EXISTS demo_words ( line STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LOCATION 'obs://your-bucket/demo/'; SELECT line, length(line) AS len FROM demo_words ORDER BY len DESC LIMIT 10;

EXTERNAL很关键,它让元数据挂在 Hive Metastore 上而数据仍在对象存储里,删表不会删数据。LOCATION指向桶内目录,末尾要不要斜杠取决于实现,建议统一带斜杠,能少一类找不到文件的报错。这条 SQL 跑通,说明「对象存储 → 计算引擎 → 结果」这条链路是通的,实验报告里综合实验那部分的证据链也就齐了。

5. 避坑与排查:五条真金白银的记录

下面这五条基本覆盖了复现过程中 90% 的卡点。每一条我都按「现象 → 原因 → 解决」写,照着对号入座比从头读日志快得多。

5.1 DataNode 起来几秒就退出,日志写 Incompatible clusterIDs

现象:jps里 DataNode 时有时无,hdfs dfsadmin -report显示 live datanodes 为 0,看 DataNode 日志能看到Incompatible clusterIDs in ... namenode clusterID = xxx; datanode clusterID = yyy。

原因:namenode 被格式化了不止一次。每次 format 都会生成新 clusterID 并写进 name 目录,而 DataNode 的 data 目录里记的还是上一次的,握手时校验不通过就直接退出。

解决:删掉所有节点上的dfs/data目录,然后在 node1 上重新 format 一次,再启动。要根治这个问题,就得把 format 当成一次性操作:格式化前确认 name 目录为空,格式化后立刻把 clusterID 记下来,后面任何异常先核对这个值。

5.2 免密配完了,ssh 还是要密码

现象:手工ssh node2能进,但脚本里ssh -o BatchMode=yes node2报Permission denied (publickey),或者 Hadoop 启动脚本卡在密码提示。

原因:三个高频原因——authorized_keys 权限不是 600、.ssh 目录权限不是 700、公钥内容被换行符或多余空格破坏。还有一种少见情况:只做了 node1 到其他节点的单向,而某些脚本需要反向登录。

解决:先ls -ld /root/.ssh && ls -l /root/.ssh/authorized_keys核对权限,再wc -l看公钥行数是不是等于机器数。权限问题用两行 chmod 就能修好,但要注意 SELinux 开着的时候即使权限对了也会被拒,getenforce确认一下是 Disabled。

5.3 集群内部能通,Web UI 从浏览器打不开

现象:节点之间 ping、ssh、hdfs 命令全正常,但在本地浏览器访问 9870 或 8088 一直转圈。

原因:两层防火墙。系统层的 firewalld 关了,但云平台的安全组没放行入方向端口,公网流量根本到不了机器。另一种情况是绑定的地址是内网 IP,而你在用公网地址访问。

解决:安全组里按需放行 9870、8088、8080、9000 的入方向,来源限制成自己的出口 IP。放行之后如果还打不开,ss -lntp | grep 9870看监听地址,如果是 127.0.0.1 或者内网地址,说明服务只绑了那一块网卡,得从配置层面调。

5.4 访问 obs:// 报 No FileSystem for scheme "obs"

现象:hadoop fs -ls obs://bucket/直接抛异常,堆栈里说找不到对应 scheme 的文件系统实现。

原因:三种可能——jar 包没放、放错了目录、放了但没重启。Hadoop 的 classpath 在 JVM 启动时固定,热拷贝 jar 进去是不生效的。还有一种是把 jar 只放到了 node1,其他节点上的任务容器里找不到。

解决:hadoop classpath | tr ':' '\n' | grep -i obs确认 jar 在搜索路径里,不在就把 jar 放到$HADOOP_HOME/share/hadoop/common/lib并全节点分发,然后stop-all.sh && start-all.sh。如果 jar 在位还报同样的错,用hadoop fs -Dfs.obs.impl=org.apache.hadoop.fs.obs.OBSFileSystem -ls obs://bucket/手工指定一次,能通说明是 core-site.xml 没同步到所有节点。

5.5 任务跑一半容器被杀,日志只有 exit code 1

现象:MapReduce 或 Spark 任务提交后,页面上一片红,容器状态失败,日志里最有用的一句是Container exited with a non-zero exit code 1,看不出根因。

原因:八成都不是代码问题,是资源。容器申请的内存超过 NodeManager 可用内存、或者物理内存超用被系统 OOM Killer 干掉,都会表现成这个。另外 env-whitelist 没配导致容器里读不到 HADOOP_MAPRED_HOME,也是同一个现象。

解决:先看 NodeManager 日志里的Killing container前后几行,确认是超内存还是启动失败。超内存就调小mapreduce.map.memory.mb,同时把yarn.nodemanager.resource.memory-mb和yarn.scheduler.maximum-allocation-mb对齐——这两个值不一致时,调度器放行、节点拒绝,报错信息会互相矛盾。启动失败就去容器日志目录看 stderr,通常能看到具体缺哪个环境变量。

6. 复现验收清单与三个能省半天的技巧

一套集群搭完之后,不要凭感觉认为「应该没问题了」。我习惯跑一份固定清单,每一项都有明确的期望输出,对不上就不算完成。这份清单在实验报告里也能直接当验收章节用。

检查项命令期望结果
进程完整jps(四台分别执行)master 三个进程,worker 两个进程
节点注册hdfs dfsadmin -reportLive datanodes = 3,全部 In Service
副本生效hdfs fsck /input -files -blocks每个块 3 个副本,无 corrupt
YARN 资源yarn node -list三个节点 RUNNING,内存数字合理
计算正确wordcount 输出词频与输入一致
对象存储连通hadoop fs -ls obs://bucket/正常列出,无异常堆栈
交互查询spark-sql 建外表后 count返回行数与源数据一致

三个技巧,都是被坑出来的。

第一个是「小数据先通管道」。不管是 wordcount 还是 Spark SQL,先用几十字节的输入跑通全链路,再换真实数据。大数据任务失败时,你很难分清是数据有问题、资源不够、还是配置错了;小数据能跑通,就排除了配置问题,剩下的范围会小很多。我一般会准备一个三行的文本文件放在 /tmp,任何时候怀疑链路有问题,先拿它跑一遍。

第二个是「日志先看 application,再看 container」。YARN 上的任务失败,yarn logs -applicationId application_xxx能一次性把 AM 和所有容器的日志拉下来,比挨个节点翻目录快得多。如果集群没开日志聚合,那就得去$HADOOP_HOME/logs/userlogs/下面找,按 application 和 container 的编号逐层进。养成先定位 application 再往里钻的习惯,能省掉大量「在错误的地方看错误的日志」的时间。

第三个是「关键节点做快照」。四台机器全部配好、验证通过之后,趁着干净状态给每台做个镜像或者快照。后面不管怎么折腾坏了,回滚回来十分钟就能重来。这个习惯在实验环境里尤其值:你总会在某个下午想试试改副本数或者换调度器,改完起不来,没有快照就得从头再来一遍两小时的搭建流程。

最后说一个教训。我第一次做这套东西的时候,图省事只在一台机器上改了配置,启动脚本一跑,三个 worker 用的还是旧参数,报错信息完全指不到配置不同步这个方向,我盯着 NameNode 日志看了快两个小时。从那以后,我每次改完配置都强制走一遍for h in node1 node2 node3 node4; do ssh $h md5sum $HADOOP_HOME/etc/hadoop/core-site.xml; done,四个哈希一致才继续下一步。多花十秒,省下两小时,这笔账怎么算都值。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表