☰
Hadoop伪分布式搭建全攻略:华南理工分布式实验2避坑指南
2026/10/8 19:43:05 网站建设 项目流程

简介:华南理工大学分布式课程实验2的完整实现方案,面向学习Java RMI远程调用开发的在校学生,解决“如何用RMI构建学生成绩/教师信息查询系统”的典型实验任务。压缩包共16个文件,包含6个Java源文件、5个编译后的class文件、2个jar依赖包,以及doc说明、txt读我文件和sql数据库脚本;其中jar包集成MySQL连接驱动,sql文件提供建表数据与初始化记录,便于直接搭建数据库运行环境。已有365人学习下载。资料完整覆盖远程接口定义、服务端注册与发布、客户端调用等核心流程,并给出从本地文件或数据库读取数据的实现思路;通过阅读源码可以直观理解RMI目录服务、远程对象绑定与客户端Stub调用机制。配套的doc文档和readme说明还能辅助快速还原实验环境、梳理提交要求,适合作为实验报告撰写、编码调试以及期末复习的参考。

1. 华南理工分布式实验2:这门课真正在考的,是把多机想象塞进一台电脑

华南理工分布式实验2,对很多同学来说第一印象是“玄学”:按教程改了五个配置文件、敲了两个启动脚本,结果 jps 只出了四个进程,NameNode 却怎么都不肯起来。这不是运气差,而是伪分布式把本该分散在多台机器的组件全部塞进了一台电脑。你要学会的不只是“照着敲”,而是弄懂每个配置项是给谁看的、进程起不来时日志里哪一行才是真异常。这篇文章按这类实验最常见的设计路径,从架构认知、hadoop 伪分布式搭建、跑通第一个 MapReduce,到高频翻车现场,完整讲一遍。适合正在赶实验进度的同学,也适合想快速搭一套可复现的分布式开发环境、但不想在资料海里迷失的从业者。

2. 伪分布式到底“伪”在哪:一台物理机如何撑起四个 Hadoop 角色

2.1 一个进程组拆出的四个角色:NameNode、DataNode、ResourceManager、NodeManager

“伪分布式”里的“伪”字,不是造假,而是模拟。在 Hadoop 的语境里,分布式不再是多台服务器通过交换机互联,而是把四类核心进程全部放在同一台 Linux 机器上,用本地回环地址 127.0.0.1 完成进程间的 RPC 通信。它仍然是一个分布式系统——存储和计算被拆分成了多个进程,也有完整的元数据服务、数据节点和调度器三层结构——只是省掉了“网络”这一维。

节点角色可以这样理解:NameNode 是仓库管理员,只记录文件清单和数据块位置,不搬货;DataNode 是真正存数据块的货架,负责读写和心跳上报;ResourceManager 是调度中心,决定把任务派给哪个节点跑;NodeManager 则是具体执行任务的工人,向 ResourceManager 汇报自己的资源状态。四者缺一个集群都不完整,功能上又各自独立。这也是为什么做分布式实验2 时,jps 的输出能直观暴露“哪个角色没起来”。

伪分布式里这些角色跑在同一台机器上,但配置、日志、端口都是分开的。日志文件里能看到 NameNode 和 DataNode 之间像真实网络一样的心跳记录、租约恢复、块上报,唯一区别是这段“网络链路”没有丢包和延迟。所以它能用来学习 HDFS 和 YARN 的工作原理,却无法用来观察真实分布式环境下的网络抖动、分区容错这类故障行为。

2.2 伪分布式刻意隐藏的三件事:故障转移、多副本、网络边界

第一件是故障转移。真集群里 NameNode 挂了,standby 节点会通过选举机制接替;DataNode 挂了,NameNode 会把副本调度到其他节点。伪分布式没有 standby,这台机器一断电,整个集群就彻底宕机,重启后还得检查元数据是否完好。你在实验里看不到任何自动故障恢复,这是正常的,不是配置错了。

第二件是多副本。hdfs-site.xml 里有个参数 dfs.replication,默认是 3,表示每个数据块存三份。在只有一台 DataNode 的伪分布式里,三份副本全部落在同一块磁盘的不同目录上。磁盘坏了数据照样丢,副本只是“分目录存放”,不具备真正的容灾意义。实验里把它改成 1 是常见的合理操作,能省空间,行为上也没有区别。

第三件是网络边界和一致性代价。真实分布式系统里最大的成本是数据跨越网络传输,慢节点、丢包、超时重传都会直接影响任务耗时。伪分布式里所有数据传输都走回环地址,延迟接近零,所以同一个作业在伪分布式上的耗时,不代表它在真集群上的耗时。这三种边界如果不在实验前想清楚,后面看 YARN 日志里的重试记录时,很容易把“网络抖动导致的 retry”误读成“代码 bug”。

2.3 从分布式实验2 走向真实分布式:锁、事务和缓存都要另起炉灶

伪分布式的价值在于让你先建立“进程视角”:知道分布式开发里,一个文件被切成数据块分布存储、一个任务被切成分片并行执行,以及协调者节点如何通过心跳掌握全局状态。有了这层认知,再去看 Redis 分布式锁、分布式缓存、分布式事务这些词,才不会只停留在概念层面。

具体来说,分布式实验2 跑完 WordCount 之后,你会接触到的实际问题大概是这样:多个服务同时操作同一行库存数据,怎么保证不超卖,这要求引入分布式事务,或者基于 ZooKeeper、Redis 的分布式锁;热点数据频繁查库,需要在业务层加分布式缓存并处理缓存一致性问题。这些组件在伪分布式环境里并不会自动出现——Hadoop 只负责计算和存储,锁和事务要靠额外中间件自己搭。提前知道这条边界,能帮你少走弯路,不至于把“实验2 跑通了”误认为“我已经懂分布式了”。

3. hadoop 伪分布式搭建五步走:从 JDK 检查到三进程全绿的配置参数

3.1 动手前先做三件事:JDK、SSH、启动用户检查

如果是在自己电脑上做实验,第一步不是下载 Hadoop,而是确认 JDK。Hadoop 3.x 需要 Java 8 或 11,用以下命令验证:

java -version

输出里有 openjdk version "1.8.0_xxx" 或 11 字样就算合格。如果本机装了多个 JDK,建议在 ~/.bashrc 里显式写入 JAVA_HOME,避免 Hadoop 脚本找到错误版本。常见做法是安装到 /usr/lib/jvm 后,把 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 追加到文件末尾,再 source ~/.bashrc。

第二步是 SSH 免密登录。Hadoop 启动脚本会用 SSH 连接本机来拉起远程进程,即使伪分布式只在本机跑,也要求 localhost 免密。逐行执行:

ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ssh localhost

最后一行 ssh localhost 如果不再提示输入密码,说明免密生效。-P '' 表示空密码,第二个命令把公钥追加进授权文件,顺序不能反,否则第一次连 localhost 还是会要密码。

第三步是决定启动用户。Hadoop 官方不推荐用 root 直接运行,但很多实验室机器只有 root 权限,如果坚持用 root 跑,需要在配置里设置 HDFS_NAMENODE_USER 等环境变量,否则会看到 Permission denied。更省事的方式是新建一个 hadoop 用户并赋予 sudo,后续所有命令都以该用户执行。这一步决定了日志目录的所有权,建议一开始就想清楚。

3.2 改好五个配置文件:核心是 hdfs-site.xml 和 core-site.xml

Hadoop 伪分布式的配置集中在 $HADOOP_HOME/etc/hadoop 目录下。需要动的文件主要是这五个:

文件作用关键参数
core-site.xml全局文件系统地址和临时目录fs.defaultFS、hadoop.tmp.dir
hdfs-site.xmlHDFS 数据块参数dfs.replication
yarn-site.xml资源调度和 Shuffle 插件yarn.nodemanager.aux-services、内存上下限
mapred-site.xml指定计算框架mapreduce.framework.name
workers声明从节点地址伪分布式填 localhost

先改 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>

fs.defaultFS 是客户端访问 HDFS 的入口地址,9000 是 NameNode 的 RPC 端口,必须和启动后监听端口一致。hadoop.tmp.dir 决定元数据和数据块的根目录,默认值是 /tmp/hadoop-${user.name},写入 /data/hadoop/tmp 可以避免系统清理 /tmp 时把集群元数据清掉,这一点后面避坑还会提到。

接着改 hdfs-site.xml:

<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>

如 2.2 节所说,单节点上副本数设为 1 最合理,默认的 3 在这里既浪费磁盘,也无法带来真正容灾。

yarn-site.xml 里需要指定 Shuffle 辅助服务,MapReduce 任务依赖它来传输中间结果:

<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> </configuration>

aux-services 写成 mapreduce_shuffle 是最容易漏的一项,漏了之后 WordCount 会卡在 Running Job 阶段。resource.memory-mb 是单节点可分配内存上限,本机内存只有 4G 时可以降到 1024。

mapred-site.xml 文件在分发包里常以 mapred-site.xml.template 存在,需要先复制再改:

cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xml
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>

最后把 workers 文件内容改成一行“localhost”(新版 Hadoop 叫 workers,老版本叫 slaves),表示所有节点都指向本机。五个文件全部改完后,可以用 grep 命令快速核对,避免漏参数。

3.3 格式化 HDFS 并启动:命令顺序和“只能一次”的底层原因

配置完成后,第一件有“破坏性”的操作是格式化:

hdfs namenode -format

格式化会生成 NameNode 的元数据镜像和 clusterID。这里要记住一个原则:正常流程下,这条命令只在第一次启动前执行。因为重复格式化会产生新的 clusterID,而 DataNode 的 current/VERSION 文件里保留着旧 clusterID,两者对不上时,DataNode 会拒绝向 NameNode 注册,表现就是 jps 里少了 DataNode。

随后启动:

start-dfs.sh start-yarn.sh

start-dfs.sh 会按 workers 文件里的地址拉起 NameNode 和 DataNode,start-yarn.sh 拉起 ResourceManager 和 NodeManager。如果前面 SSH 免密没配好,这两个脚本会中途卡住等待密码输入。

3.4 三件套验证:jps、Web UI、hdfs 命令

启动后先看进程:

jps

健康的伪分布式应该同时出现四个进程:NameNode、DataNode、ResourceManager、NodeManager。如果少了一个,优先去 $HADOOP_HOME/logs 下找对应日志文件,比如 hadoop-hadoop-datanode-主机名.log,用 tail -n 50 看最后的异常。

然后确认 Web UI。Hadoop 3.x 的 NameNode 管理界面默认端口是 9870,YARN 资源调度界面是 8088:

curl -I http://localhost:9870 curl -I http://localhost:8088

输出 HTTP/1.1 200 即正常。注意大量老教程写的是 50070,那是 Hadoop 2.x 的默认端口,版本不同不要硬套。再用 HDFS 自带命令确认数据节点状态:

hdfs dfsadmin -report

观察输出里的 Live datanodes 数量是否为 1,以及 Configured Capacity 是否接近本机磁盘大小。到这里,伪分布式集群已经搭起来,下一步可以往 HDFS 里放文件、跑计算任务了。

4. 用官方 jar 包跑通 WordCount:输入输出路径与 Running Job 卡住的排查

4.1 找到 hadoop-mapreduce-examples 并准备输入数据

搭建完成只是第一步,分布式实验2 真正要交的往往是“跑起来一个 MapReduce 作业”。最简单、也最适合用来验证环境的是官方自带的 WordCount 示例。先确认 jar 包存在:

ls $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar

版本号会随安装包变化,用通配符 *.jar 就能避免记错版本。确认之后,先在 HDFS 上创建输入目录并上传文件:

hdfs dfs -mkdir -p /input hdfs dfs -put $HADOOP_HOME/etc/hadoop/*.xml /input hdfs dfs -ls /input

这里容易踩的第一个坑是“文件在哪”。hdfs dfs -put 之后文件已经进入 HDFS,不在本地文件系统。后面如果报 Input path does not exist,基本都是因为本地路径不存在,或文件没有先放到 HDFS。

4.2 输出目录“已存在”的两种处理方式

输入就绪后,用 hadoop jar 提交作业:

hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /input /output

如果 HDFS 上已经存在 /output 目录,会直接报错:

Output directory /output already exists

MapReduce 设计上不会覆盖旧输出目录,这是防止误删数据的一层保护。两种处理方式:一是换一个不存在的目录名,比如 /output-20250101;二是先删掉旧目录再跑:

hdfs dfs -rm -r /output

实际做实验时我一般用第二种,因为反复调试时目录越堆越多,最后交报告反而要清理。

4.3 作业跑完后,从哪里看分布式行为

作业完成后,用以下命令查看结果:

hdfs dfs -cat /output/part-r-00000

part-r-00000 是归约阶段写出的结果文件,文件名以 part-r 开头表示来自 Reducer。到这一步,实验2 的核心流程已经通了。但别急着关页面,建议顺手打开 http://localhost:8088 看一下 YARN 界面里的 Application 状态,能看出作业分成了多少个 Map 和 Reduce 任务、每个任务运行了多久、失败了几次又重试了几次。这是伪分布式环境里少数能直观观察到“调度”行为的地方。

拓展一步说,WordCount 跑通只是起点。真实系统里的分布式锁、订单与库存分布式事务、分布式缓存一致性问题,都不是 Hadoop 能解决的,需要单独引入 ZooKeeper、Redis 或消息队列。实验2 让你看到的是“任务分片并行执行”这个底层事实,后面学中间件时,很多概念都能落回这张图里。

5. 避坑清单:分布式实验2 最容易翻车的五个现场与对应日志定位

5.1 jps 里少了 DataNode,日志报 clusterID 不一致

现象:start-dfs.sh 执行完没有报错,但 jps 只看到 NameNode,DataNode 进程不存在。打开 hadoop-hadoop-datanode-主机名.log,能看到类似 InconsistentFSStateException 或者 clusterID 不匹配的异常。

原因:这是格式化次数过多导致的。第一次格式化生成 clusterID 后,NameNode 和 DataNode 的 VERSION 文件都会记录它;第二次格式化只重置了 NameNode 侧,DataNode 侧还留着旧 ID。两边对不上,DataNode 自然拒绝注册。

解决:如果集群里还没有重要数据,最直接的办法是“后悔药”——把临时目录整个删掉,重新格式化:

stop-all.sh rm -rf /data/hadoop/tmp hdfs namenode -format start-dfs.sh

注意 /data/hadoop/tmp 就是 3.2 节里 hadoop.tmp.dir 配的路径,如果你用的默认 /tmp 路径,文件会分散在 /tmp/hadoop-${user.name} 下,也要一并删掉。

5.2 Web UI 打不开:50070 还是 9870,先分清楚版本

现象:浏览器输入 http://localhost:50070 一直转圈,或者直接拒绝连接;curl 本地端口也没响应。

原因:50070 是 Hadoop 2.x 的 NameNode 默认端口,Hadoop 3.x 换成了 9870。老教程、博客截图满天飞,照着抄很容易被带偏。另外 8088 是 YARN 的端口,3.x 没有变化。

解决:先确认 Hadoop 版本:

hadoop version

再用对应端口测试。如果是 3.x,访问 http://localhost:9870;如果端口没监听,再从日志看 NameNode 到底有没有起来。注意,改了 core-site.xml 里的 fs.defaultFS 端口,Web UI 端口不随它变,9870 是固定配置。

5.3 WordCount 卡在 Running Job,容器反复被杀

现象:作业提交后,终端一直停在进度条,YARN 界面上 Application 是 RUNNING,但容器 Container 反复失败重试,日志里频繁出现物理内存超限的报错。

原因:伪分布式环境内存本来就紧张,如果本机只有 4G,YARN 默认给每个容器分配的内存却很大,NodeManager 一分配就超过机器实际可用内存,触发系统 OOM 或 YARN 自身监控杀进程。

解决:把 yarn-site.xml 里的资源参数调低,比如:

<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>1024</value> </property> <property> <name>yarn.app.mapreduce.am.resource.mb</name> <value>512</value> </property> <property> <name>yarn.app.mapreduce.am.command-opts</name> <value>-Xmx384m</value> </property>

改完重启 YARN:stop-yarn.sh 再 start-yarn.sh。这一步是作业卡住时最值得先检查的参数组,别一上来就怀疑代码。

5.4 启动脚本报 Permission denied,或 ssh localhost 总要密码

现象:第一次跑 start-dfs.sh 就报权限不足,或者脚本执行到一半停下来开始提示输入密码。日志里看不到具体异常,只有一句 Permission denied。

原因:常见三种:一是用 root 跑 Hadoop 但没有设置 HDFS_NAMENODE_USER 等环境变量;二是 ~/.ssh 目录或 authorized_keys 文件权限不对,SSH 拒绝读取公钥;三是 HADOOP_HOME 指向了根目录,脚本没找到正确的启动用户。

解决:如果是 root 用户,在配置文件开头追加:

export HDFS_NAMENODE_USER=root export HDFS_DATANODE_USER=root export HDFS_SECONDARYNAMENODE_USER=root export YARN_RESOURCEMANAGER_USER=root export YARN_NODEMANAGER_USER=root

如果 SSH 问题,重新执行 3.1 节的免密配置,并确认 ~/.ssh 目录权限是 700,authorized_keys 权限是 600。别把权限放宽到 777,SSH 反而会拒绝读取。

5.5 格式化成功后 DataNode 依然起不来:日志没有异常但进程反复退出

现象:重新格式化后,NameNode 正常,DataNode 进程出现几秒后消失,日志里没有明显的 Exception,最后一行只是 SHUTDOWN_MSG。

原因:DataNode 的 current 目录里数据块文件和 NameNode 元数据不是同一代。格式化虽然解决了 clusterID,但数据块目录残留会导致 DataNode 启动时做块上报校验,跑到一半异常退出,而且异常经常被打日志的顺序掩盖。

解决:把 hadoop.tmp.dir 下 datanode 目录单独删掉再启动,不需要重新格式化整套元数据:

rm -rf /data/hadoop/tmp/dfs/data start-dfs.sh

如果还不放心,就按 5.1 的方式完整删干净再格式化一遍。伪分布式没什么重要数据,删了重来成本很低,别抱着“修复”的心态折腾,这不是生产集群。

6. 验证脚本与日志思维:把“会跑命令”升级成“能定位问题”

实验做到最后,我建议你花十分钟写一个检查脚本,把“每次启动后手动验证”变成一条命令。脚本很简单,但能帮你养成先确认状态、再动手排障的习惯:

#!/bin/bash for name in NameNode DataNode ResourceManager NodeManager; do if jps | grep -q "$name"; then echo "[OK] $name is running" else echo "[FAIL] $name is missing" fi done curl -s -o /dev/null -w "NameNode WebUI: %{http_code}\n" http://localhost:9870 curl -s -o /dev/null -w "YARN WebUI: %{http_code}\n" http://localhost:8088

把这段存成 check.sh,chmod +x check.sh,以后每次启动集群后执行一次,三秒钟就能确认环境是否就绪。比逐个 jps、逐个 curl 高效得多。

比脚本更重要的是日志思维。很多人卡住时的第一反应是把整段报错复制去搜索,其实 Hadoop 的日志文件就在 $HADOOP_HOME/logs 下,后缀是 .log。定位问题的顺序应该是:先看对应的进程日志 → 找 Exception 或 Caused by → 把异常行复制去搜索 → 再回来看上下文。异常信息里真正有用的往往只有一两行,比如 Cluster ID mismatch、Address already in use、物理内存超限。“Caused by”后面跟的才是根因,前面那堆堆栈是外壳。

我用这个顺序带过不少人做类似的分布式实验,凡是愿意先在日志里翻三分钟的,最后都能自己解决;反着一上来就重装重配的,反而越搞越乱。这套“先看状态、再读日志、最后动手”的习惯,比单纯记住配置参数值更值钱。希望你做分布式实验2 时,也能把这份从容带进后续的分布式锁、分布式事务这些更复杂的场景里。希望帮到你。

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

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

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

立即咨询