这篇文章想写清楚一件事:在 Ubuntu 22.04 上,用三台虚拟机把一套 Hadoop 完全分布式集群从零搭起来。我前后用 VMware 搭过很多次 Hadoop 环境,从伪分布式到三节点完全分布式都折腾过,中间踩过的坑不少,所以这篇直接把完整流程和排错经验一起写出来,争取你看完能少走弯路。
这套方案的目标很明确:在本地电脑上用三台 Ubuntu 22.04 虚拟机,分别扮演一个 master 和两个 slave 节点,组成一套能正常跑 HDFS 存储和 YARN 计算的集群。整个过程涵盖虚拟机安装、网络规划、SSH 免密、JDK 安装、Hadoop 配置、集群初始化、功能验证,最后再补几个我实际遇到过的高频问题。
适合的人群主要有三类:正在做大数据课程实验的学生、准备搭开发环境自学的初学者,以及需要在本地复现分布式环境的工程师。生产级高可用集群不在本文讨论范围内,这里追求的是“用最少资源跑通全流程,同时把原理讲明白”。
1. 搭建前必须想清楚的事:版本、网络与角色规划
很多人一上来就跟着网上的帖子直接敲命令,结果做到一半发现网段不对、主机名对不上、端口不对,前前后后折腾一整天。我的建议是,动手之前先把三台机器的角色规划好,至少要确定三件事:虚拟化软件用什么、每台机器装什么系统、IP 段怎么划分。
1.1 为什么选择“三台虚拟机”而不是伪分布式
Hadoop 的伪分布式模式(Pseudo-Distributed)只需要一台机器,所有守护进程都跑在本机,适合刚接触 Hadoop 时了解基本命令。但伪分布式有个问题:它没法真正模拟跨节点的数据分布和任务调度,很多分布式场景下的坑只有多节点才能真正暴露出来。
三台虚拟机是一个性价比非常高的学习方案。一台做 master,跑 NameNode 和 ResourceManager;两台做 slave,跑 DataNode 和 NodeManager。这样既覆盖了 HDFS 的“一主多从”架构,也覆盖了 YARN 的“ResourceManager + NodeManager”调度模型。我见过有人用五台、七台虚拟机搭集群,其实学习阶段三台完全够了,等以后要学 HBase、Hive、Kafka 再加节点也不迟。
虚拟机的好处是随便折腾,坏了就回滚快照,不用担心把宿主机搞崩。如果机器配置允许,比如内存 16G 以上、硬盘剩 100G 左右,跑三台虚拟机很轻松。
1.2 集群角色分配与IP规划参考表
下面是我这次搭建使用的规划,每一台机器都是 2 核 CPU、2G 内存,硬盘 60G。如果你的宿主机配置偏低,内存可以降到 1.5G,但不要再低了,否则 JVM 启动就会很吃力。
| 主机名 | 角色 | IP 地址 | 主要运行的进程 |
|---|---|---|---|
| master | NameNode / ResourceManager | 192.168.137.101 | NameNode、ResourceManager、SecondaryNameNode |
| slave1 | DataNode / NodeManager | 192.168.137.102 | DataNode、NodeManager |
| slave2 | DataNode / NodeManager | 192.168.137.103 | DataNode、NodeManager |
这里有一个很重要的细节:主机名不建议用 “hadoop1、hadoop2、hadoop3” 这种没有辨识度的命名,最好直接用 master / slave1 / slave2,在后面配置 core-site.xml 和 yarn-site.xml 时一眼就能看出哪台是主节点。
IP 网段的话,我用的是 VMware 的 NAT 模式默认网段 192.168.137.0/24。如果你用 VirtualBox,网段可能不一样,或者你在办公室网络里可能已经有其他 DHCP 服务,所以一定要先确认虚拟网络编辑器里的子网 IP。我的做法是:在 VMware 菜单栏点击“编辑 -> 虚拟网络编辑器”,找到 VMnet8 那一条,看 NAT 设置里的子网 IP 是多少,然后再规划静态 IP。你也可以把整个集群换成桥接模式,让虚拟机直接用路由器分配的地址,但那样 IP 地址容易变,需要额外留意。
1.3 虚拟机安装时需要注意的几个选项
这个环节如果只搭一台虚拟机还好,搭三台时如果每一步都重复点一遍图形界面,会非常费时间。我用的办法是:先完整安装好第一台 Ubuntu 22.04 Server,配置好基础环境,然后直接克隆出另外两台,再分别修改主机名和 IP。这样比重新安装三遍快很多。
安装 Ubuntu 22.04 时有几个选项需要特别注意:
ISO 选 ubuntu-22.04.x-live-server-amd64.iso,这个在官网和国内镜像站都能下载。学习 Hadoop 建议装 Server 版而不是 Desktop 版,因为 Server 版没有图形界面,内存占用低,而且 Hadoop 本身就不需要图形界面。如果你实在不习惯纯命令行,装 Desktop 版也可以,但要把自动登录和锁屏关掉,避免虚拟机闲置时锁屏卡住。
磁盘分区那里,新手直接选“Use entire disk”就行,但要注意把虚拟机的虚拟磁盘设置得大一些。我记得第一次搭 Hadoop 时只给了 20G,结果格式化 NameNode 时磁盘满了,日志里报错特别难排查。建议 50G 起步,60G 比较稳。
创建用户时,我直接建了一个叫 hadoop 的普通用户,密码也设成 hadoop 相关的口令。后面所有 Hadoop 操作都用这个用户执行,不要用 root 跑 Hadoop 集群。原因后面讲环境变量和权限时会提到,这是很多新手容易踩的坑。
安装完成后,建议先打个快照,命名“刚装好的Ubuntu系统”。这个快照是后续所有操作的“后悔药”。
2. 基础环境统一配置:三台机器同步操作
这一部分讲的是三台虚拟机都要做的通用配置,包括主机名、IP、hosts 映射、SSH 免密、JDK。如果只有一台机器配置好了,另外两台没配,后面集群启动时会出现各种连不上、找不到主机的问题。
2.1 修改主机名、固定IP(netplan 配置)
Ubuntu 22.04 修改主机名的方式很简单,直接改 /etc/hostname 文件。比如在 master 上:
sudo hostnamectl set-hostname master执行完可以用 hostname 命令确认。同样的操作在 slave1、slave2 上分别执行,把主机名改成对应的名字。
接下来是固定 IP。Ubuntu 22.04 用的网络配置工具是 netplan,配置文件在 /etc/netplan/ 目录下,文件名可能是 00-installer-config.yaml 或类似的名字,先看一下:
sudo ls /etc/netplan/我这边拿到的文件名是 00-installer-config.yaml,用 vim 或 nano 编辑:
sudo vim /etc/netplan/00-installer-config.yaml把内容改成下面这样。注意 ens33 是你的网卡名称,可以用 ip addr 命令查看,不同机器可能叫 ens32、ens160 之类,以实际为准。
network: version: 2 ethernets: ens33: dhcp4: no addresses: - 192.168.137.101/24 routes: - to: default via: 192.168.137.2 nameservers: addresses: [192.168.137.2, 223.5.5.5]这里解释一下为什么网关和 DNS 是这两个值。VMware NAT 模式下,虚拟机的默认网关一般是 x.x.x.2,也就是 VMnet8 的网关地址。DNS 我除了填 NAT 网关,还加了一个 223.5.5.5 作为备用,网络抖动时不容易因为 DNS 解析失败导致 apt 下载或 ping 域名出错。
改完后执行:
sudo netplan applynetplan apply 是热加载,一般不需要重启。但如果发现网络不生效,可以执行 sudo reboot。slave1 和 slave2 的 addresses 分别改成 192.168.137.102 和 192.168.137.103,其他部分保持一致。
2.2 /etc/hosts 配置与网络连通性验证
主机名和 IP 固定之后,还需要在每个节点的 /etc/hosts 文件里把集群所有机器的映射关系写好。这样无论是 SSH 还是 Hadoop 内部通信,都可以直接使用主机名,不依赖 DNS 服务。
在三台机器上用 root 权限编辑 /etc/hosts(使用 sudo)。
sudo vim /etc/hosts在最后追加三行:
192.168.137.101 master 192.168.137.102 slave1 192.168.137.103 slave2配置好之后,建议在每个节点上做一轮连通性测试,避免后面启动集群时才发现网络不通。测试命令如下:
ping -c 4 master ping -c 4 slave1 ping -c 4 slave2正常情况下每台机器都能 ping 通另外两台。如果不能 ping 通,优先检查 IP 是否配置正确、VMware 虚拟网络编辑器里的 DHCP 和 NAT 设置是否与自己规划的网段一致。
2.3 SSH免密登录配置与权限问题
Hadoop 启动脚本是通过 SSH 远程登录到每台机器去启动守护进程的。如果每次登录都需要输密码,start-dfs.sh 会卡在那里,根本跑不起来,所以 SSH 免密是必须配置的一步。
我推荐的做法是:在每台机器上都生成密钥,然后把每台机器的公钥都分发到集群所有机器的 authorized_keys 里。这样做虽然比“只在 master 生成密钥并分发”多几步,但能避免以后在 slave 上手动操作 HDFS 或执行其他跨节点命令时又需要输密码。
在两台机器的普通用户 hadoop 下分别执行:
ssh-keygen -t rsa -b 4096生成过程中直接一路回车,不设置 passphrase。然后把公钥拷贝到集群内每台机器(包括本机):
ssh-copy-id hadoop@master ssh-copy-id hadoop@slave1 ssh-copy-id hadoop@slave2在三台机器(至少是 master,但建议三台都执行一遍)都跑完这些命令后,测试一下免密是否成功:
ssh master ssh slave1 ssh slave2第一次连接会提示确认 host key,输入 yes 即可。之后再次连接应该直接进入对方的 shell,不需要密码。
这里有一个非常常见的坑:免密配置不生效,通常是 ~/.ssh 目录和文件权限不对。SSH 对这几个文件的权限要求很严格,目录权限不能超过 700,authorized_keys 文件权限不能超过 600。我之前遇到过在 Windows 上用 SSH 工具编辑文件导致权限混乱的情况。如果测试失败,手动修正权限:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys2.4 安装JDK并配置JAVA_HOME
Hadoop 是基于 Java 写的,所以每台机器都必须装 JDK。这里先说版本选择:Hadoop 3.3.x 官方支持 Java 8 和 Java 11。网上很多教程还在用 JDK 8,但 Ubuntu 22.04 的 apt 源里默认包含的是 OpenJDK 11 和 17,为了省事且稳定,我推荐 OpenJDK 11。
直接在三台机器上执行:
sudo apt update sudo apt install -y openjdk-11-jdk安装完成后,先确认 Java 路径。这个路径在配置 JAVA_HOME 时要用的:
which java readlink -f $(which java)在我的机器上,Java 的实际安装路径是 /usr/lib/jvm/java-11-openjdk-amd64。接下来编辑当前用户的环境变量文件:
vim ~/.bashrc在文件末尾追加以下内容:
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 export PATH=$PATH:$JAVA_HOME/bin执行 source ~/.bashrc 让配置生效,然后验证:
java -version看到 openjdk version “11.0.x” 就说明 JDK 装好了。注意这个操作要在三台机器上都做一遍,很多人在 master 上配好了 JAVA_HOME,slave 上没配,启动集群时 DataNode 直接报 “Error: JAVA_HOME is not set”。
3. Hadoop安装与核心配置详解
基础环境就绪后,终于到了核心环节:安装 Hadoop 并修改配置文件。这部分我建议不要急着复制粘贴,先把每个配置文件的含义搞清楚。配置出错的时候,不理解含义就很难排查。
3.1 选择版本、下载与解压
Hadoop 的版本选择直接决定了后面很多操作细节。现在生产环境里 Hadoop 3.x 早就是主流了,3.2、3.3 都用得比较多。我这篇用的是 3.3.6,这个版本稳定、资料多,踩坑时比较容易搜到答案。
下载地址我建议用清华镜像站,速度比官网好很多:
https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.6/在每台机器上下载并解压,或者只在 master 上下载后通过 scp 复制到另外两台。我这边为了方便,用 wget 在每台机器上下载,然后统一解压到 /usr/local/hadoop 目录:
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz sudo tar -xzf hadoop-3.3.6.tar.gz -C /usr/local sudo mv /usr/local/hadoop-3.3.6 /usr/local/hadoop解压完成后一定要修改目录属主,让 hadoop 用户拥有读写权限。否则后面启动集群时,Hadoop 无法在安装目录下创建临时文件和日志:
sudo chown -R hadoop:hadoop /usr/local/hadoop为什么要强调这件事?因为我见过很多教程复制粘贴命令,结果 Hadoop 目录属于 root 用户,普通用户执行 start-dfs.sh 时疯狂报权限错误,又找不到是哪里出的问题。这一步虽然不起眼,但能省掉很多麻烦。
3.2 理解Hadoop集群中的角色:哪个进程跑在哪台机器
配置之前,先花两分钟把 Hadoop 集群里各个角色搞清楚,后面看配置文件和启动日志会轻松很多。
HDFS 部分有两个核心角色。NameNode 负责管理文件系统的元数据,比如文件目录、文件被切成了哪些块、每个块存放在哪些节点上,它相当于整个 HDFS 的“大脑”。DataNode 负责真正存储数据块,并向 NameNode 定期汇报自己存储了哪些块。集群里通常只有一个 NameNode(学习环境),DataNode 可以有多个。
YARN 部分也有两个核心角色。ResourceManager 是集群资源分配的“调度中心”,它决定哪个应用能拿到多少 CPU 和内存。NodeManager 是每台机器上的“资源管家”,它负责启动容器、监控资源使用情况,并定期向 ResourceManager 汇报。
对应到我们的三台机器规划就是:master 上跑 NameNode + ResourceManager + SecondaryNameNode(辅助合并编辑日志),slave1 和 slave2 上跑 DataNode + NodeManager。这个规划最终会在配置文件里体现出来。
3.3 五个核心配置文件的完整说明
Hadoop 的配置文件都在 $HADOOP_HOME/etc/hadoop/ 目录下。我们需要修改的主要是五个文件。下面一个一个过。
先看 hadoop-env.sh。这个文件里最核心的是 JAVA_HOME。Hadoop 启动脚本会读取这个变量来决定用哪个 JDK。用 vim 打开后,找到 # export JAVA_HOME= 这一行,改成:
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64如果不确定路径,先用 ls 确认一下目录是否存在。注意网上有些教程会在 /etc/profile 里配 JAVA_HOME,然后 hadoop-env.sh 里不配置,这样也偶尔能用,但最可靠的做法是两个地方都配好,让 Hadoop 脚本在启动时一定找得到 JDK。
接下来是 core-site.xml。这个文件定义的是 Hadoop 全局配置,我们主要改两项。fs.defaultFS 决定 HDFS 的访问入口,hadoop.tmp.dir 决定 Hadoop 临时文件存放位置,也就是 NameNode 和 DataNode 数据目录的根路径。
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://master:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/home/hadoop/hadoopdata</value> </property> </configuration>这里有两个重点。第一,hdfs://master:9000 中的 master 必须跟 /etc/hosts 里的主机名一致,否则客户端和节点之间无法通过主机名解析。第二,hadoop.tmp.dir 默认值是 /tmp/hadoop-${user.name},但 /tmp 目录在系统重启后可能被清理,一旦 NameNode 的元数据丢了,整个 HDFS 里的文件就找不回来了。所以我把它改到 /home/hadoop/hadoopdata,并且提前创建这个目录:
mkdir -p /home/hadoop/hadoopdata然后配置 hdfs-site.xml。这个文件控制 HDFS 的行为。我们要配置 NameNode 和 DataNode 的数据存储路径,以及文件副本数。
<configuration> <property> <name>dfs.namenode.name.dir</name> <value>file:///home/hadoop/hadoopdata/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///home/hadoop/hadoopdata/data</value> </property> <property> <name>dfs.replication</name> <value>2</value> </property> </configuration>dfs.namenode.name.dir 存储的是 NameNode 的元数据,相当于 HDFS 的文件“户口本”。dfs.datanode.data.dir 存储的是真正的数据块。fs.replication 表示一个文件默认的副本数量,三台节点时填 2 或 3 都可以。我这里填 2 是因为每台虚拟机磁盘空间有限,存两份既能起到备份效果,又不至于太吃空间。
然后是 mapred-site.xml。在 Hadoop 3.x 版本里,这个文件不再提供模板文件,需要手动创建。它控制 MapReduce 计算框架的运行模式:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>mapreduce.framework.name 的值设置为 yarn,意思是用 YARN 来调度和管理 MapReduce 作业。如果设置成 local,MapReduce 就会在本地运行,不利用集群资源,那分布式就没有意义了。
最后是 yarn-site.xml。这个文件配置 YARN 的资源调度行为。核心配置有两项:ResourceManager 跑在哪台机器,以及 NodeManager 启动时加载的辅助服务。
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>master</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration>yarn.resourcemanager.hostname 是告诉 NodeManager 去哪里找 ResourceManager,这里填 master 就行。yarn.nodemanager.aux-services 必须设置成 mapreduce_shuffle,因为 MapReduce 作业在 reduce 阶段需要通过 shuffle 机制从各个 mapper 拉取中间结果,这个服务是专门干这件事的。很多新手漏配这一项,结果作业提交后一直卡住,日志里报 Shuffle 相关的错误。
3.4 配置workers节点列表
在 Hadoop 3.x 版本中,定义集群从节点的文件叫 workers,不再是 2.x 版本的 slaves。编辑:
vim /usr/local/hadoop/etc/hadoop/workers把这个文件里默认的 localhost 删掉,改成两个数据节点的主机名,每行一个:
slave1 slave2这个文件的作用是告诉 master 在执行 start-dfs.sh 和 start-yarn.sh 时,要去哪些机器上启动 DataNode 和 NodeManager。如果你漏改这个文件,集群启动后就会神奇地发现只有一个 DataNode,而且是在 master 上。
3.5 环境变量与常见权限设置
为了让 hadoop、hdfs 等命令在任何目录下都能直接使用,需要配置 HADOOP_HOME 环境变量。继续编辑 ~/.bashrc,在之前 JDK 配置底下追加:
export HADOOP_HOME=/usr/local/hadoop export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin执行 source ~/.bashrc 后,验证一下:
hadoop version能打印出 Hadoop 版本信息,就说明基本环境已经齐了。
另外还要注意,Hadoop 在运行过程中会产生大量日志,默认放在 $HADOOP_HOME/logs 目录下面。如果偷偷发现集群启动失败,却没有日志可查,可以检查一下这个目录的权限:
mkdir -p /usr/local/hadoop/logs sudo chown -R hadoop:hadoop /usr/local/hadoop/logs这一步我加了完全是因为当时遇到过“日志目录不能写导致 daemon 直接退出的情况”。看起来不太起眼,但排查时很讨厌。
4. 集群初始化、启动与功能验证
配置写完,接下来是检验成果的时候。先把所有节点都开机并确认网络正常,然后在 master 上执行格式化、启动、验证三步走。
4.1 格式化NameNode(格式化的含义与注意事项)
格式化 NameNode 是初始化 HDFS 的第一步,它会在 NameNode 的数据目录下生成初始的元数据,并生成一个唯一的 clusterID。在 master 上执行:
hdfs namenode -format执行过程中会输出大量日志,最后显示 “successfully formatted” 就说明成功了。
这里必须强调一个我在实操中踩过的坑:格式化操作只能执行一次。如果你在集群已经启动过之后再次格式化,NameNode 会生成一个新的 clusterID,但 DataNode 的本地数据目录里还是旧 clusterID,启动后 DataNode 会拒绝连接,Web 界面显示 Live Nodes 为 0。如果确实需要重新格式化,必须把所有节点上的数据目录都清理干净,然后再格式化,最后再启动。
清理命令是:
rm -rf /home/hadoop/hadoopdata/data/* # 三台机器都要清理,尤其是 master 的 name 目录和 slave 的 data 目录这一点单独记下来,可以减少很多不必要的排错时间。
4.2 启动HDFS和YARN,判断进程是否正常
格式化完成后,先启动 HDFS,再启动 YARN。在 master 上执行:
start-dfs.sh start-yarn.sh为什么不直接执行 start-all.sh?start-all.sh 虽然一条命令能启动所有服务,但如果过程中某个服务启动失败,日志混杂在一起,排查起来比较痛苦。分步启动的好处是能准确定位问题在 HDFS 还是 YARN。
启动过程中,master 会自动 SSH 到 slave1 和 slave2 上启动对应进程,日志里能看到 Added a new node,表示远端节点启动成功。
启动完成后,用 jps 命令检查各节点进程。jps 是 JDK 自带的小工具,专门显示 Java 进程信息,Hadoop 所有守护进程都是 Java 进程,所以可以直接用 jps 来看。
正常情况下,三台机器输出应该是这样的:
master 节点:
NameNode ResourceManager SecondaryNameNode Jpsslave1 和 slave2 节点:
DataNode NodeManager Jps如果某个进程缺失,比如 slave 上没有 DataNode,那就要去对应的日志目录查看报错信息了。
这里再补充一个有用的命令。在 master 上执行:
hdfs dfsadmin -report这个命令会列出当前活跃的 DataNode 数量、每台 DataNode 的存储容量和使用情况。如果输出里能看到 slave1 和 slave2 两个节点且状态正常,就说明 HDFS 层面已经 OK 了。
4.3 通过Web UI和命令行双重验证
进程层面验证完,再通过 Web UI 确认一遍更放心。Hadoop 3.x 的 NameNode Web 界面端口是 9870,不是网上很多老教程里的 50070。ResourceManager 的 Web 界面端口是 8088。
在宿主机浏览器里访问:
http://192.168.137.101:9870打开的是 HDFS 管理界面,能看到文件系统目录、DataNode 状态、集群容量等。再访问:
http://192.168.137.101:8088打开的是 YARN 资源管理界面,能看到 NodeManager 列表和正在运行的作业。
很多新手在这一步打不开网页,第一个反应是操作系统防火墙,但 Ubuntu 默认没有开 ufw,所以更常见的原因其实是虚拟机的网络模式问题。确认在宿主机上能 ping 通 192.168.137.101,再检查浏览器访问的 IP 是否和虚拟机 IP 一致。如果还是不行,可以在虚拟机内部用 curl 测试:
curl http://localhost:9870能返回一堆 HTML 代码,说明 Web 服务本身是正常的,问题出在宿主机到虚拟机的网络链路上。
4.4 跑一个WordCount验证分布式计算全链路
进程都起来了,Web 界面也能打开,最后跑一个 MapReduce 作业验证整个集群真的能干活。最经典的例子就是 WordCount,统计一段文本中每个单词出现的次数。Hadoop 发行包自带了示例程序,不需要自己写代码。
先在 HDFS 里创建输入目录:
hdfs dfs -mkdir -p /wordcount/input把 Hadoop 的某个配置文件上传作为输入数据:
hdfs dfs -put /usr/local/hadoop/etc/hadoop/core-site.xml /wordcount/input/确认上传成功:
hdfs dfs -ls /wordcount/input接下来在 master 上提交 WordCount 作业:
hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /wordcount/input /wordcount/output注意输出目录 /wordcount/output 必须是不存在的,如果已经存在,作业会直接报错。提交后终端会滚动输出 Map 和 Reduce 的进度,最后能看到类似 “File System Counters”、“Map-Reduce Framework” 的统计信息。
执行完成后查看结果:
hdfs dfs -cat /wordcount/output/part-r-00000如果能看到 word 和对应计数的输出,就说明这一整套集群从存储到计算都已经正常工作了。这时候可以说,三台虚拟机的 Hadoop 集群搭建算是真正完成。
5. 常见问题与排查技巧实录
集群搭得再顺利,也难免遇到几个波折。这里把我在多次搭建过程中遇到的典型问题、排查思路和解决方案整理一下。这些问题在 Stack Overflow 和各大技术社区里出现频率都很高,提前了解能省下不少时间。
5.1 DataNode起不来的经典原因:clusterID不一致
现象:master 上执行 start-dfs.sh 后,slave 上的 DataNode 进程没有出现,查看 $HADOOP_HOME/logs/hadoop-hadoop-datanode-slave1.log,里面报告 “Incompatible clusterIDs”。
原因:我前面提过,格式化 NameNode 后再启动集群,如果各节点数据目录里的 clusterID 和 NameNode 不一致,DataNode 会被拒绝注册。这个情况在重复搭建多节点集群时太常见了,常常是 master 上的 name 目录已经被清理并重新格式化,但 slave1 和 slave2 的 data 目录还留着旧数据。
解决:在所有节点上删除 HDFS 数据目录下的内容,然后在 master 上重新格式化 NameNode。
# 所有机器执行 rm -rf /home/hadoop/hadoopdata/name/* rm -rf /home/hadoop/hadoopdata/data/* # 只在 master 执行 hdfs namenode -format删除前确认目录正确,别把 HDFS 数据目录和系统其他目录搞混。之后重新 start-dfs.sh 就能正常启动。
5.2 Web界面打不开或Live Nodes显示为0
现象一:宿主机浏览器访问 http://192.168.137.101:9870 无法打开。
排查思路:先确认 Web UI 进程已启动。执行 jps 看 master 上是否有 NameNode 进程。然后检查网络连通性,宿主机 ping 虚拟机 IP,如果 ping 不通,检查 VMware 网络设置和虚拟机内部 IP。如果 ping 得通但浏览器打不开,尝试用虚拟机内部 curl localhost:9870,能返回代码就说明是外部访问被拦,检查 Windows 防火墙是否拦截了虚拟机网段的入站连接。注意 Linux 网络栈的默认行为,以及是否启用过 ufw。
现象二:Web UI 能打开,但显示 Live Nodes 为 0,或者只有一个 Live Node。
排查思路:先看 slave 上 DataNode 是否启动,如果没启动,看日志找原因。很多时候问题出在 core-site.xml 里 fs.defaultFS 写错了主机名,导致节点之间无法正确注册。先检查 hosts 文件是否在所有节点都维护正确。其次确认 workers 文件里没有残留 localhost。最后确认数据目录没有重复使用不同 clusterID 的旧数据。
5.3 免密登录失败与known_hosts问题
现象:执行 start-dfs.sh 时,终端提示输入密码,而不是自动免密连接。
原因:SSH 免密配置没生效,可能是公钥没有正确分发,也可能是文件权限不对。
排查:先在 master 上手动执行 ssh slave1,观察是否有密码提示。如果失败,检查 ~/.ssh 目录权限是否为 700,authorized_keys 权限是否为 600。如果权限没问题,再把每台机器的公钥重新 ssh-copy-id 一遍。
另外一个奇怪但实际会遇到的问题是:前期测试免密正常,但一段时间后又开始要密码。可能是系统某个进程重建了 home 目录里的 .ssh,或者有管理员权限的用户把 authorized_keys 覆盖了。我的建议是,遇到这类问题直接重新 ssh-copy-id 一次,比深挖原因更快。
5.4 内存不足、磁盘不足导致作业失败
现象:集群启动没问题,但提交 WordCount 后作业一直卡在 ACCEPTED 或 RUNNING 状态,最后失败。
原因:典型的是 YARN 容器内存分配超出物理内存。默认情况下,NodeManager 会认为物理内存有很多,然后给每个容器分配较大的内存,可虚拟机只有 2G 内存,于是作业还没跑就 OOM 了。
解决:在 yarn-site.xml 里增加下面这些配置,限制每个容器的内存上限:
<property> <name>yarn.nodemanager.resource.memory-mb</name> <value>1536</value> </property> <property> <name>yarn.scheduler.maximum-allocation-mb</name> <value>1536</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>256</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property>yarn.nodemanager.vmem-check-enabled 设置为 false,可以避免虚拟内存检查导致容器被误杀。如果你改完配置发现集群起不来,记得把配置同步到所有节点的 Hadoop 安装目录,然后重启 YARN:
stop-yarn.sh start-yarn.sh磁盘不足也是常见问题。默认虚拟机给 20G 磁盘,格式化完 NameNode、复制软件包,再存几个输入文件,可能就满了。df -h 查看磁盘使用率,如果接近 100%,清理 apt 缓存或调整虚拟机磁盘大小。
5.5 善用虚拟机快照,降低重装成本
这一条不是报错排查,但却是能让你少走很多弯路的重要技巧。虚拟机最强大的功能就是快照和克隆。我的习惯是每完成一个重要阶段就创建一个快照,命名清晰,比如:
- 刚装好Ubuntu未配置
- 网络和JDK已配置
- Hadoop配置完成
- 集群初始化成功后可正常运行
这样如果后续操作把环境搞坏了,不用重新装系统或者重新敲一遍配置,直接回滚到上一个快照点,几分钟就能恢复。
举例来说,如果配置完 Hadoop 后发现某个配置文件改得很混乱,可以直接回滚到“Hadoop配置完成”之前的快照,重新修改。如果你做实验时把 HDFS 里存了很多无用文件,或者不小心删了重要目录,快照也能救你。把快照当作“集群上车险”,成本低但关键时刻非常有用。
另外再提醒一下,克隆虚拟机时如果选择“链接克隆”,会依赖母盘,母盘被删除后克隆机就起不来。建议创建“完整克隆”,虽然慢一点、占空间,但独立性和稳定性都好很多。克隆完之后记得修改主机名和 IP,否则两台机器同名同 IP,SSH 和 Hadoop 都会乱套。
写完这些,我回想了一下自己第一次搭三节点集群时的经历,前前后后花了整整一个周末,踩遍了上面所有坑。如果你按这篇顺序一步一步来,周末之内搭完应该是没问题的。后面如果想让这套集群更有“生产感”,可以试着把 Zookeeper、HBase、Hive 也装上去,让 Hadoop 生态逐步丰满起来。