☰
Hadoop伪分布式实验:Linux环境、HDFS与WordCount排错
2026/10/27 2:12:12 网站建设 项目流程

简介:这份大数据实验一指导文档面向刚接触大数据课程的学生与自学者,围绕 Linux 虚拟机搭建、常用 Shell 命令和 Hadoop 伪分布式环境三条主线展开,帮助读者在单机上补齐后续实验所需的基础操作能力。压缩包仅含 1 个 docx 文件,约 289KB,篇幅集中,便于按实验目的、实验平台、内容要求与结果总结逐项查阅。文档覆盖 VirtualBox 与 Ubuntu 18.04/16.04 的安装准备,cd、ls、mkdir、rmdir、cp、mv、rm、cat、tac、more、head、tail、touch、chown、find、tar、grep 等命令练习,以及 Hadoop 3.1.3 伪分布式安装、环境变量配置、WordCount 实例验证和 HDFS 目录创建、文件复制与查看等常用操作。已有 978 人学习,适合作为课程实验参考、操作清单和复习提纲,也可用于对照检查基础环境是否搭建完整。

1. 实验一真正在考什么:从 Linux 命令行到 HDFS 的一次贯通

“大数据实验 实验一:熟悉常用的 Linux 操作和 Hadoop 操作”,标题看起来像一份命令清单,实际考的是四层依赖能不能一次串起来:操作系统的账户与权限、SSH 的免密登录、Java 运行时、Hadoop 自己的四个配置文件。这四层里任何一层没打牢,最后都会以hadoop fs -ls抛出一堆看不懂的异常收场,而报错信息往往指向一个你从没直接动过的路径——这是最典型的黑匣子体验。下面按真实搭建顺序走一遍:先立环境,再练命令,再改配置,再跑 HDFS 和 WordCount,最后把最容易翻车的地方逐条拆开。第一次接触伪分布式的人可以照着做,带实验的人也可以拿它对照排查。

2. Linux 基础环境四步立住:账户、SSH 免密、目录规划与常用命令

2.1 专用账户与目录规划:为什么不该用 root 跑守护进程

拿到实验指导书之后,很多人的第一反应是su root,然后一路装下去,装完能跑,交完报告就忘。问题在于 Hadoop 的每个守护进程都以“启动它的那个用户”的身份写日志、写数据目录。你只要用 root 启动过一次,后面换成普通账户就会在/tmp或数据目录上撞到Permission denied,而那条报错指向的路径你根本没直接操作过。

我一般在开跑前定三条约定:一个专用普通账户(习惯叫hadoop)、一个统一安装根目录(/opt/module)、一个独立数据目录(/data/hadoop)。账户负责权限边界,目录负责路径可预期,权限负责让守护进程能写进去。三件事十分钟能做完,却能省掉后面两小时的排查。

# 1. 建专用账户,别用 root 跑守护进程 sudo useradd -m -s /bin/bash hadoop sudo passwd hadoop # 2. 统一安装根目录与数据目录,后续所有路径都从这里展开 sudo mkdir -p /opt/module sudo mkdir -p /data/hadoop/{name,data,tmp} sudo chown -R hadoop:hadoop /opt/module /data/hadoop # 3. 给普通账户临时提权,避免脚本执行到一半停下来等密码 echo "hadoop ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/hadoop sudo chmod 440 /etc/sudoers.d/hadoop

useradd -m会同时建家目录,-s /bin/bash保证登录后有正常 shell,否则ssh localhost会直接退出、什么提示都不给。/opt/module是社区里常见的安装惯例,好处是所有组件(Hadoop、JDK)都放在一层里,后面写JAVA_HOME和HADOOP_HOME时路径短、不容易写错。chown -R的递归很关键,只改父目录的话子目录仍然属于 root,DataNode 写块文件时会失败。/etc/sudoers.d/下单独放文件比直接改sudoers安全,440权限是 sudo 的硬性要求,写成644会直接拒绝加载。

把/data/hadoop/tmp单独分出来,是因为 Hadoop 的hadoop.tmp.dir默认落在/tmp下,而/tmp在多数发行版里会被系统清理任务定期清空。临时文件被清掉之后,NameNode 的元数据和 DataNode 的块就对不上,症状是“昨天还能跑,今天启动就报错”——这种玄学问题十有八九源于此。

2.2 SSH 免密登录:start-dfs.sh 能不能一键起来全看这一步

start-dfs.sh的工作方式,是在本机通过 ssh 分别拉起 NameNode、DataNode、SecondaryNameNode。它没有别的进程管理机制,就是循环调用ssh。所以免密没配好,脚本要么卡在反复输密码,要么直接Permission denied退出,而且三个进程可能只起来一个,jps看上去“起了一半”。

# 切到专用账户再操作,密钥要生成在正确的人的家目录下 su - hadoop # -P '' 表示空口令,-f 指定路径,避免覆盖已有密钥 ssh-keygen -t rsa -b 4096 -P '' -f ~/.ssh/id_rsa # 公钥写入授权列表 cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # 权限必须收紧,sshd 的 StrictModes 会拒绝过宽的权限 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys # 验证:能不带密码直接登进去才算通过 ssh localhost

血泪经验在最后两行。~/.ssh必须是700,authorized_keys必须是600,很多发行版的 sshd 默认开启StrictModes,权限一旦放宽到组或其他用户可读,就会静默忽略这个文件,然后回头找你要密码。更隐蔽的一种情况是密钥生成在 root 账户下、却用hadoop去启动服务,ssh localhost单独测试能过(因为当时是 root),start-dfs.sh就过不去。

ssh-keygen -t rsa -b 4096里-t是算法、-b是密钥长度;-P ''给空口令,是为了让脚本调用时不被口令交互拦住,不是省略安全设置——这台机器只是本地实验环境,私钥也不要往外拷。

2.3 文件与文本命令的最小可用集:find、grep、awk、sed、tail

实验指导书里的 Linux 命令通常列几十个,但真正天天用、且能组合起来解决问题的是五六个。练的时候不要孤立地敲,要带着“我要在 Hadoop 目录里找点什么”的目的去用。

# 定位:限制深度,避免在几十万文件的目录里全盘扫描 find /opt/module -maxdepth 3 -type f -name "*.xml" # 过滤:从日志里捞出异常行,-n 带上行号方便定位 grep -n "ERROR\|Exception" /opt/module/hadoop/logs/*namenode*.log | tail -n 50 # 截字段:-F 指定分隔符,取第 1、3 列 awk -F'\t' '{print $1 "\t" $3}' /data/hadoop/tmp/sample.tsv | head -n 20 # 批量替换:-i 原地改,改之前先不加 -i 看一遍输出 sed -i 's#hdfs://oldhost:9000#hdfs://localhost:9000#g' /opt/module/hadoop/etc/hadoop/core-site.xml # 跟踪:实时看 DataNode 启动过程中的反馈 tail -f /opt/module/hadoop/logs/*datanode*.log

find的-maxdepth是性能开关,不限深度在/下跑一次能卡住好几分钟;-type f排除目录,否则-name会匹配到同名目录。grep -n的行号在对照日志上下文时尤其有用,tail -n 50只取最后 50 行,是因为 Hadoop 日志动辄几万行,全量输出反而看不见关键那几行。

awk -F'\t'里的-F是字段分隔符,默认是任意空白。处理 HDFS 导出的数据时,制表符和空格混用非常常见,显式指定分隔符能避免整行被当成一列。sed -i是原地修改,第一次用建议先不加-i,确认替换结果正确再落盘——我见过把core-site.xml里fs.defaultFS的值整体替换掉、导致文件结构损坏的例子,改之前备份一份cp core-site.xml core-site.xml.bak是最便宜的安全保障。注意sed用#而不是/作分隔符,是因为替换内容里本身含//。

2.4 权限与进程:chmod、chown、jps、ss 的判断顺序

启动失败时,判断顺序比命令本身更重要。我的习惯是:先看进程在不在,再看端口通不通,最后看权限对不对。顺序反了就容易在权限上折腾半天,结果发现进程压根没起来。

命令典型场景容易踩的点
jps -l确认 Java 进程与主类只显示当前用户的进程,用 root 敲会“看不到”
ss -lntp看 9000/9870/8088 是否监听需要权限才能显示进程名
chmod调整脚本可执行位不要图省事给 777
chown -R修数据目录属主漏掉-R导致子目录仍是旧属主
kill结束残留进程先 TERM 后 KILL,直接-9会丢元数据
# 进程层:先确认守护进程真的起来了 jps -l # 网络层:9000 是 RPC,9870 是 NameNode Web UI,8088 是 YARN ss -lntp | grep -E '9000|9870|8088|9864' # 权限层:只给必要的执行位,别用 777 chmod 755 /opt/module/hadoop/bin/*.sh chown -R hadoop:hadoop /data/hadoop # 收尾:先温和终止,给进程写元数据的机会 kill $(jps | awk '/DataNode/{print $1}')

jps的一个坑是它只列当前用户启动的 JVM。用 root 敲jps看不到hadoop用户起的 NameNode,很容易误判成“没起来”。ss -lntp里-l是监听状态、-n不做域名解析、-t是 TCP、-p显示进程,四个参数一起用才够快。至于kill,先发默认的 TERM 信号,让进程有机会把内存里的元数据落盘,直接kill -9在 NameNode 上用过一次就够记一辈子——恢复起来要么靠 SecondaryNameNode 的检查点,要么重新格式化,两条路都不好走。

3. Hadoop 伪分布式配置:四个 XML 文件和一个 env 文件逐项改

3.1 单机模式、伪分布式与完全分布式:实验一为什么选中间那个

Hadoop 有三种运行模式,选错模式是白折腾两小时的常见原因。单机模式(standalone)开箱即用、不需要任何配置,但它根本不启动 HDFS 和 YARN,所有程序在本地 JVM 里跑,hdfs dfs -ls这类命令会直接告诉你“没有文件系统”。完全分布式至少三台机器,涉及主机名解析、跨机免密、时间同步,属于实验二之后的内容。

伪分布式是折中:所有守护进程都在一台机器上,但彼此通过 RPC 通信,走完整的 HDFS 读写路径和 YARN 调度路径。它的价值在于,你能用一台机器观察到真实集群里的所有角色——NameNode、DataNode、ResourceManager、NodeManager,能看懂进程之间的关系,也能踩到 90% 的配置坑。

模式需要改配置是否启动 HDFS/YARN适用阶段
单机否否只验证 MapReduce 逻辑
伪分布式是,4 个 XML + env是,单机多进程实验一标准形态
完全分布式是,另加主机与免密是,多机实验二及之后

判断自己当前在哪个模式,最简单的办法是看core-site.xml里有没有fs.defaultFS。没有这一项,Hadoop 就走本地文件系统,你 put 进去的文件压根没进 HDFS,后面hdfs dfs -ls /空空如也就是必然的。

3.2 core-site.xml 与 hdfs-site.xml:两个必改项和默认值陷阱

四个配置文件都在$HADOOP_HOME/etc/hadoop/下。改之前全部备份一遍,出错能一分钟回滚,这比事后回忆改了哪一行靠谱得多。

<!-- core-site.xml:入口地址与临时目录 --> <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/data/hadoop/tmp</value> </property> </configuration>
<!-- hdfs-site.xml:副本数与元数据/数据落盘位置 --> <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///data/hadoop/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///data/hadoop/data</value> </property> </configuration>

fs.defaultFS是整套配置的中枢,客户端靠它决定连哪个 NameNode,写错端口或主机名,所有hdfs dfs命令都会连不上。用localhost还是主机名,取决于/etc/hosts里有没有把主机名解析到127.0.0.1;如果解析不到,NameNode 启动时会抛UnknownHostException,而报错里通常只显示一个主机名,不看/etc/hosts很难联想到。

dfs.replication默认是 3,伪分布式只有一台 DataNode,副本数设成 3 会导致块永远处于“副本不足”状态,hdfs fsck报一堆 under-replicated,虽然不影响读写但看着闹心,也容易让人误以为集群坏了。设成 1 是伪分布式的标准做法。

hadoop.tmp.dir是第二个陷阱。不显式配置时,HDFS 的元数据默认落在/tmp/hadoop-${user.name}下,系统清理任务一动手,NameNode 的fsimage就没了,下次启动直接报“目录不存在,请格式化”。把name.dir和data.dir用file://绝对路径写死,等于给集群上了个保险。

3.3 mapred-site.xml、yarn-site.xml 与 hadoop-env.sh:让作业真的落在 YARN 上

只改前两个文件,HDFS 能起来,但提交 MapReduce 作业会走本地模式,jps里看不到 ResourceManager,也体验不到 YARN 调度。剩下两个文件和 env 脚本补的就是这一块。

<!-- mapred-site.xml:指定计算框架为 YARN --> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
<!-- yarn-site.xml:NodeManager 的附属服务与 ResourceManager 地址 --> <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>localhost</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> </configuration>

yarn.nodemanager.aux-services的值必须是mapreduce_shuffle,少一个下划线、多一个 s,NodeManager 能起来但 MapReduce 作业会卡在 map 100% reduce 0% 不动,这个症状极具迷惑性。resource.memory-mb默认取机器物理内存的一个比例,在只有 4G 内存的虚拟机里常常导致容器申请不到资源,作业一直处于 ACCEPTED 状态,显式调小到 2048 是常用做法。

# hadoop-env.sh 里追加,注意不要覆盖原有的 export export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 export HDFS_NAMENODE_USER=hadoop export HDFS_DATANODE_USER=hadoop export HDFS_SECONDARYNAMENODE_USER=hadoop export YARN_RESOURCEMANAGER_USER=hadoop export YARN_NODEMANAGER_USER=hadoop

JAVA_HOME要写绝对路径,用readlink -f $(which java)反推最稳,因为很多发行版把java放在/usr/bin的软链上,直接写/usr/bin/java会被当成目录。Hadoop 3 里那几个*_USER变量是启动脚本检查用的,不写会看到ERROR: Attempting to operate on hdfs namenode as root之类的提示,或者提示用户变量未定义——这个报错信息说得含糊,第一次见很难定位到是 env 脚本缺行。

3.4 格式化与启动:一次成功该看到哪几个进程

# 只执行一次,重复执行会引发 clusterID 不一致 hdfs namenode -format # 启动 HDFS 与 YARN start-dfs.sh start-yarn.sh # 期望看到 6 个进程 jps

hdfs namenode -format会初始化dfs.namenode.name.dir目录,生成fsimage和VERSION文件。格式化成功时控制台会打印Storage directory ... has been successfully formatted,同时给出一个 clusterID,记下这一行。伪分布式环境里我建议把“只格式化一次”写在便利贴上贴屏幕边——这不是夸张,重复 format 是实验一最高频的翻车原因,处理方式在第 5 章展开。

jps期望看到 6 个进程:NameNode、DataNode、SecondaryNameNode、ResourceManager、NodeManager、Jps。少任何一个都别急着往下走,先去看$HADOOP_HOME/logs/下对应角色的日志,.log结尾的是运行日志,.out结尾的是标准输出,多数启动失败的原因在.out的最后 20 行里写得明明白白。

注意:start-dfs.sh和start-yarn.sh的返回码是 0 并不代表进程起来了,它们只是把 ssh 命令发出去。必须用jps或ss -lntp二次确认。

4. HDFS 与 WordCount 跑通:从 put 一个文件到读出 part-r-00000

4.1 HDFS 的八个动作:一次完整的本地与集群往返

HDFS 命令分两套写法,hadoop fs和hdfs dfs,前者能操作更广的文件系统,后者专指 HDFS。做实验时用hdfs dfs,语义更清楚,也不容易误操作到本地目录。

# 建目录:-p 递归创建,父目录不存在也不报错 hdfs dfs -mkdir -p /user/hadoop/input # 上传:本地路径在前,HDFS 路径在后 hdfs dfs -put /opt/module/hadoop/etc/hadoop/*.xml /user/hadoop/input # 列出:-R 递归,看子目录时用 hdfs dfs -ls /user/hadoop/input # 查看内容:小文件直接 cat,大文件用 -tail hdfs dfs -cat /user/hadoop/input/core-site.xml # 看容量:-h 人类可读,-s 显示总计 hdfs dfs -du -h -s /user/hadoop/input # 下载回本地 hdfs dfs -get /user/hadoop/input/core-site.xml /tmp/ # 改权限:目录给 755,脚本类文件才需要执行位 hdfs dfs -chmod -R 755 /user/hadoop # 删除:-r 递归,-f 跳过确认,生产上慎用 -f hdfs dfs -rm -r /user/hadoop/input

-put会把本地文件复制到 HDFS,源文件保留;-moveFromLocal则是剪切语义,本地文件会消失,两个命令在实验报告里经常被混写。-du -h -s里-s是 summary,不加它会把每个子文件都列一遍,看总量时反而累赘。-rm -r和-rm -f组合使用要小心,-f会跳过确认提示,在 HDFS 上删掉的东西没有回收站(除非单独配置了 Trash),删了就是删了。

一个常被忽略的点:HDFS 的路径是逻辑路径,/user/hadoop会映射到dfs.namenode.name.dir下的实际目录结构,但这个映射不是一对一的文件对应关系,块文件(blk_*)和.meta校验文件是分开存的。所以不要试图在 Linux 里直接catHDFS 的块文件,读出来是二进制。

4.2 WordCount 的最小输入与提交命令

跑通 HDFS 之后,WordCount 是验证 MapReduce 链路最快的例子。它不需要自己写代码,Hadoop 自带示例 jar 包里就有。

# 1. 造一份最小输入,三行文本足够看出词频 echo -e "hadoop mapreduce hdfs\nyarn hdfs hadoop\nmapreduce yarn hdfs" > /tmp/wc-input.txt # 2. 建输入目录并上传,输出目录不要预先创建 hdfs dfs -mkdir -p /user/hadoop/wc/input hdfs dfs -put /tmp/wc-input.txt /user/hadoop/wc/input # 3. 提交作业,jar 用通配符避免记版本号 hadoop jar /opt/module/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.*.jar \ wordcount /user/hadoop/wc/input /user/hadoop/wc/output # 4. 看结果 hdfs dfs -ls /user/hadoop/wc/output hdfs dfs -cat /user/hadoop/wc/output/part-r-00000

hadoop jar会自动把作业提交到mapreduce.framework.name指定的框架,配置成yarn就走 YARN,配置成local就在当前 JVM 里跑完。所以前面mapred-site.xml那一项没改的话,这里能出结果但jps里看不到 ResourceManager,作业执行时间也短得可疑——这是判断“到底走没走 YARN”的一个土办法。

输入输出路径都是 HDFS 路径。输出目录必须不存在,这是 MapReduce 的保护机制:作业失败重跑时如果直接覆盖,上一次的部分结果就没法对比了。所以第二次跑同一条命令,必须先hdfs dfs -rm -r /user/hadoop/wc/output。

提示:作业提交后控制台会打印Job job_xxxx submitted、map 100% reduce 100%、Job job_xxxx completed successfully。卡在map 0% reduce 0%通常是 YARN 资源不足,卡在map 100% reduce 0%则优先查aux-services配置。

4.3 读懂输出目录:part-r-00000、_SUCCESS 与 .crc 各是什么

第一次ls输出目录,看到三四个陌生文件容易发懵。它们的含义其实很规整:

文件含义说明
part-r-00000第 0 个 reducer 的输出r表示 reduce 阶段产物,编号从 0 开始
part-m-00000第 0 个 mapper 的输出没有 reducer 或 reduce 数为 0 时出现
_SUCCESS作业成功标记零字节空文件,供调度系统判断是否完成
.part-r-00000.crc校验文件HDFS 侧生成,不要手动改

part-r-00000里的内容是单词\t词频的制表符分隔格式。上一步的三行输入跑完,能读到hadoop 2、hdfs 3、mapreduce 2、yarn 2这样的结果,词按字典序排列。文件名的数字是分区编号,reduce 任务数设为 2 时会同时出现part-r-00000和part-r-00001,这一点在做多 reduce 实验时会用到。

_SUCCESS是个零字节文件,用hdfs dfs -cat读出来什么都没有,别以为出错了。它的存在本身就是信号,很多调度工具就靠这个文件判断上游作业是否完成。

.crc文件是 HDFS 的校验和,用来检测块在磁盘上的损坏。它们由 DataNode 自动维护,-put和-get时校验一次。手动删掉不会影响读取,但下次校验周期会重新生成,属于“看着碍眼但别动”的那类文件。

5. 避坑与排查:实验一里五个高频翻车点

配置做完、命令也敲完,剩下的时间基本都花在排查上。下面五条是我见过频率最高、且报错信息最容易误导人的。

5.1 反复格式化之后 NameNode 起不来:clusterID 不一致

现象:jps里只有Jps,没有NameNode;看logs/*namenode*.log,最后几行写着java.io.IOException: Incompatible clusterIDs in /data/hadoop/data/current: namenode clusterID = CID-xxxx; datanode clusterID = CID-yyyy。

原因:hdfs namenode -format执行了不止一次。每次格式化都会给 NameNode 目录生成新的 clusterID,而 DataNode 目录里还留着上一次的 ID,两边对不上,NameNode 拒绝启动。也可能是只删了name目录没删data目录,或者反过来。

解决:停掉所有进程,把dfs.namenode.name.dir和dfs.datanode.data.dir指向的两个目录整体删空,重新格式化一次。这是一次“后悔药”,代价是 HDFS 上的数据全丢,所以只适合实验环境。

stop-dfs.sh rm -rf /data/hadoop/name/* /data/hadoop/data/* hdfs namenode -format start-dfs.sh

根治办法其实更简单:格式化之前先ls一下 name 目录,非空就别格。真需要重来,走上面三步,不要指望 NameNode 自己在两个 ID 之间挑一个。

5.2 SSH 免密“看着配了”,start-dfs.sh 还是要密码

现象:单独敲ssh localhost能直接进去,敲start-dfs.sh却提示Permission denied (publickey,password),或者卡在Starting namenodes on [localhost]一直没动静。

原因有三种。第一种是~/.ssh或authorized_keys权限过宽,sshd 的StrictModes静默忽略了这个文件——注意是静默,日志里只有一行Authentication refused: bad ownership or modes,很容易被跳过。第二种是密钥生成在 root 家目录下,而服务是用hadoop用户启动的。第三种是/etc/ssh/sshd_config里PubkeyAuthentication被关掉了,虽然少见但确实存在。

解决:先确认当前用户,再查权限,最后看 sshd 配置。

whoami ls -ld ~/.ssh ~/.ssh/authorized_keys # 期望输出 drwx------ 和 -rw------- chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys sudo grep -E 'PubkeyAuthentication|StrictModes' /etc/ssh/sshd_config

改完 sshd 配置要sudo systemctl restart sshd。这台机器上还有一个细节:ssh localhost走的是127.0.0.1,而start-dfs.sh里用的可能是主机名,如果/etc/hosts没把主机名映射到本地回环,两条路径的认证结果可能不一样。

5.3 JAVA_HOME 没写死,脚本报找不到 Java

现象:手动敲hadoop version正常输出,但start-dfs.sh报ERROR: JAVA_HOME is not set and could not be found,或者作业提交时抛Could not find or load main class。

原因:JAVA_HOME只在交互式 shell 的.bashrc里 export 过。ssh 非交互登录(start-dfs.sh内部就是这种)默认不读.bashrc,只读.bash_profile或.profile。另一种情况是hadoop-env.sh里export JAVA_HOME=那行还带着#注释。

解决:把JAVA_HOME写死在$HADOOP_HOME/etc/hadoop/hadoop-env.sh里,这是所有启动脚本都会 source 的文件,不受登录方式影响。路径用readlink -f $(which java)反推,再去掉末尾的/bin/java。

readlink -f $(which java) # 输出类似 /usr/lib/jvm/java-11-openjdk-amd64/bin/java grep -n "JAVA_HOME" /opt/module/hadoop/etc/hadoop/hadoop-env.sh

改完不需要重启任何东西,下次启动脚本生效。这条坑的特点是“手动能跑、脚本不能跑”,如果只按交互式经验判断,会一直在.bashrc里找原因。

5.4 jps 里没有 ResourceManager 或 NodeManager

现象:start-yarn.sh打印Starting resourcemanager和Starting nodemanagers,返回码 0,但jps里就是没有这两个进程。

原因:最常见的是yarn-site.xml里yarn.nodemanager.aux-services拼写错误,或者值写成了mapreduce-shuffle(多了个连字符)。其次是内存不足,NodeManager 启动时按yarn.nodemanager.resource.memory-mb申请资源,虚拟机内存不够会被系统 OOM 杀掉。第三是yarn.resourcemanager.hostname写了个解析不到的名字。

解决:先看日志尾部,再改配置。

tail -n 40 /opt/module/hadoop/logs/*resourcemanager*.log tail -n 40 /opt/module/hadoop/logs/*nodemanager*.log free -h

日志里Exiting with status 1之前那几行才是真正原因。内存不够就先stop-yarn.sh,把resource.memory-mb调到 1024 再起。aux-services 拼写错误在日志里体现为InvalidAuxServiceException,比较显眼,改完重启即可。

5.5 作业提交被拦:安全模式与输出目录已存在

现象一:hdfs dfs -put报Cannot create file ... Name node is in safe mode。原因是 NameNode 启动后处于安全模式,等 DataNode 上报足够的块才自动退出。如果 DataNode 压根没起来,它会一直卡着。这时候hdfs dfsadmin -safemode leave能临时放行,但根因没解决,下次重启照样卡。

现象二:WordCount 报org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/user/hadoop/wc/output already exists。原因是 MapReduce 不覆盖已有输出目录,这是设计如此,不是 bug。

解决:安全模式先查 DataNode,jps里没有就去看 DataNode 日志,多数是data.dir权限或 clusterID 问题(回到 5.1)。确认 DataNode 正常后再hdfs dfsadmin -safemode get看状态,一般几秒内会自己退出。输出目录直接删掉重跑:

hdfs dfs -rm -r /user/hadoop/wc/output hadoop jar /opt/module/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.*.jar \ wordcount /user/hadoop/wc/input /user/hadoop/wc/output

养成习惯:每次重跑作业前先删输出目录,比看到报错再删快得多。

6. 把环境自检写成一个脚本:一次跑完比反复重启省半小时

排查次数多了会发现,五成问题出在“没确认环境就往下走”。与其每次启动失败后凭记忆一条条敲,不如把检查项固化成一个脚本,改完配置先跑它,通过再提交作业。

#!/usr/bin/env bash # check_env.sh:伪分布式环境自检,任一项失败即退出 set -e echo "[1/5] 当前用户与 Java" whoami readlink -f "$(which java)" echo "[2/5] SSH 免密" ssh -o BatchMode=yes -o ConnectTimeout=3 localhost "echo ssh-ok" echo "[3/5] 守护进程" jps -l | grep -E 'NameNode|DataNode|ResourceManager|NodeManager' || { echo "进程缺失,去看 \$HADOOP_HOME/logs/*.out"; exit 1; } echo "[4/5] 端口监听" ss -lntp | grep -E '9000|9870|8088' echo "[5/5] HDFS 健康度" hdfs dfsadmin -report | head -n 12 hdfs fsck / -files -blocks | tail -n 3

set -e让脚本遇到第一个失败就停,避免“后面全是连锁报错”的噪音。ssh -o BatchMode=yes是关键:它禁止任何交互式提问,免密没配好会立刻失败而不是卡住等密码,正好把第 5.2 条那类问题提前暴露。ConnectTimeout=3防止在网络不通时挂太久。hdfs dfsadmin -report输出里Live datanodes (1)这一行是伪分布式的标准形态,如果显示 0,说明 DataNode 没注册上,后面的操作全都不必做。hdfs fsck只看最后三行,是因为正常集群的输出有几千行,你要的信息只有“块数、副本状态、健康状况”这三个数。

这个脚本我一般放在~/bin/下,加进PATH,改完任何一个 XML 就跑一次,三十秒出结果,比启动失败后翻日志快得多。用了两年多,最大的体会是:环境类问题的排查成本,几乎全部来自“不确定自己在哪一层”,而不是“不知道解法”。把层次固定下来,剩下的就是查表。

有一点提醒,脚本里不要用hdfs dfs -ls /当健康检查——空目录也会返回 0,看起来一切正常,实际 DataNode 可能一个都没起来。用dfsadmin -report里的 Live datanodes 数量判断,才是有意义的信号。我自己在这上面翻过一次车,写进脚本之后就没再犯。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询