很久没写Hadoop相关的实操文章了,这两天刚好帮一个零基础的朋友从裸机开始搭了一套完全分布式环境,踩了一路的坑,也把很多以前知其然不知其所以然的点彻底搞明白了。趁热把整个过程整理出来,从规划、安装、配置到启动验证,全流程走一遍。这篇东西不假设你有任何Hadoop基础,但希望你至少会基本的Linux命令,比如cd、vim、tar这类,如果你连这些也不熟,建议先花半小时熟悉一下再来看。
1. 为什么我不推荐你从伪分布式开始学
很多教程喜欢先让你搭伪分布式,也就是在一台机器上同时跑NameNode、DataNode、ResourceManager、NodeManager。伪分布式的确能帮你快速跑通一个WordCount,但它会掩盖一个严重的问题:你对“分布式”这三个字没有任何体感。你没有亲手配置过集群节点之间的通信,没有体验过SSH免密的必要性,也不明白为什么DataNode连不上NameNode的时候日志会那么让人崩溃。
完全分布式是正儿八经的多台机器协作:一台机器当“领导”,其余的当“干活的”。你把文件扔进去,它会切块分发到不同机器上,这一过程涉及网络通信、心跳汇报、元数据管理。这些东西不亲手搭一遍,只在文档里看,永远建立不起来直观认识。
所以我的建议是:哪怕你手上只有一台8G内存的电脑,也建议用虚拟机拆出3台来,这里面的网络配置、角色划分、进程通信,都是真实分布式环境的缩小版,踩过的坑将来上了生产环境一样能碰上,只是规模不同。
另外声明一下:这篇文章以Hadoop 3.3.6为基准,JDK用的是Hadoop官方推荐的Java 8(OpenJDK 1.8.0_392)。虽然新版Hadoop开始支持Java 11甚至17,但生产环境里用Java 8的仍然占绝大多数,而且Hadoop 3.x对Java 8的支持最成熟,零基础起步选它最稳。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与集群规划:先把丑话说在前面
2.1 硬件与系统要求
所谓完全分布式,至少需要两台机器,一台做Master,一台做Worker。但在实际学习中,两台的容错率太低,比如你把NameNode和SecondaryNameNode放在同一台机器上,配置稍微写错就容易起冲突,排查起来也麻烦。我这里用的是三台虚拟机:1台Master + 2台Worker,这是最经典、最适合入门、也不算浪费资源的方案。
每台虚拟机的配置建议如下:
| 配置项 | 最低要求 | 推荐配置 | 说明 |
|---|---|---|---|
| CPU | 1核 | 2核 | 编译和启动阶段会比较吃力 |
| 内存 | 2GB | 3~4GB | 至少保证2GB可用,否则Java进程起不来 |
| 磁盘 | 20GB | 40GB | 主要是HDFS的存储目录和日志会占用空间 |
| 操作系统 | CentOS 7 | CentOS 7.9 / Ubuntu 20.04 | 本文以CentOS 7.9为例 |
| 网络 | NAT模式 | NAT模式 | 虚拟机之间互通,并能够访问外网 |
内存这个点我必须多说一句。很多人用1G内存的虚拟机跑Hadoop,结果启动的时候各种奇奇怪怪的报错,比如进程启动后马上就消失了,或者JVM直接OOM。Hadoop的每个Java进程默认就会占几百MB内存,3台机器加起来光跑基础服务就需要6GB以上的物理内存。如果你电脑是16GB内存,建议每台虚拟机给3GB左右,总共9GB,剩下的留给宿主机,这样最稳。
2.2 主机名与IP地址规划
这一步是很多零基础教程忽略但极其重要的环节。Hadoop集群内部是通过主机名进行通信的,HDFS的配置文件和Hadoop自身的脚本都大量依赖主机名的解析。如果你不给每台机器配好主机名并写入/etc/hosts,后面启动集群时就会出现“连不上”的诡异问题,日志里还看不出明显原因。
我的建议规划如下:
| 角色 | 主机名 | IP地址 | 运行的服务 |
|---|---|---|---|
| Master | hadoop-master | 192.168.10.101 | NameNode、SecondaryNameNode、ResourceManager、HistoryServer |
| Worker1 | hadoop-worker1 | 192.168.10.102 | DataNode、NodeManager |
| Worker2 | hadoop-worker2 | 192.168.10.103 | DataNode、NodeManager |
这里有一个非常关键的决策点:谁当Master? 很多人习惯在Windows或者自己的主力开发机上直接装,但我强烈建议所有节点都使用Linux虚拟机,因为Hadoop的生产环境基本不会部署在Windows上,而且Linux环境下的排查工具(比如ss、jps、lsof)用起来比Windows顺手得多。
2.3 基础环境配置:关闭防火墙与SELinux
这一步容易被新手忽略。CentOS默认开启了firewalld,Hadoop各个节点之间的通信会被它拦掉,导致集群看起来启动了,但DataNode一直连不上NameNode。我在第一次搭建时就吃过这个亏,检查了半小时配置文件,最后发现就是防火墙没关。
bash复制# 三台机器都执行
systemctl stop firewalld
systemctl disable firewalld
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
关闭SELinux后需要重启虚拟机生效,实际上如果你只是临时学习,不重启也能继续,但建议还是重启一次,让环境干净一点。
3. 基础环境配置:SSH免密与JDK安装
3.1 修改主机名并配置hosts映射
先给三台机器设置主机名,这个操作要在每台机器上分别执行:
bash复制# hadoop-master 上执行
hostnamectl set-hostname hadoop-master
# hadoop-worker1 上执行
hostnamectl set-hostname hadoop-worker1
# hadoop-worker2 上执行
hostnamectl set-hostname hadoop-worker2
然后三台机器都要编辑/etc/hosts,把三台机器的映射关系都放进去:
bash复制cat >> /etc/hosts <<EOF
192.168.10.101 hadoop-master
192.168.10.102 hadoop-worker1
192.168.10.103 hadoop-worker2
EOF
为什么需要hosts文件?因为Hadoop集群内部的通信会通过主机名去解析IP。如果你每台机器只配了自己的hosts而没配别人的,那么在Master上通过主机名去连Worker1时,它会先查hosts文件,查不到就报UnknownHostException。虽然也可以通过配置DNS服务来解决,但用hosts文件对于小规模集群是最简单直接的方式。
3.2 SSH免密登录配置:理解原理才能不踩坑
SSH免密登录是Hadoop全分布式搭建里最经典的坎。很多人照着教程执行完ssh-keygen和ssh-copy-id,却仍然要输密码,原因往往出在文件权限或者弄混了密钥类型上。
先用一个比喻解释一下RSA非对称加密的原理:你生成一对钥匙,公钥(.pub文件)相当于一把只能锁不能开的锁,私钥相当于唯一的钥匙。你把锁发给别人,别人用锁把你的身份信息锁进一个盒子里,你用自己的钥匙打开盒子,就完成了一次身份验证。在SSH里,这个“盒子”就是服务器生成的challenge。
具体操作步骤:
bash复制# 在三台机器上分别生成密钥对(一路回车即可)
ssh-keygen -t rsa -b 4096 -P ""
这里有个小细节:-P "" 表示私钥不需要密码保护。如果不加这个参数,回车后会让你设置私钥密码,然后每次SSH连接都要输入私钥密码,这就是很多人配置完免密后仍然要输密码的原因之一。
生成完成后,把Master的公钥分发给三台机器(包括自己):
bash复制# 在 hadoop-master 上执行
ssh-copy-id hadoop-master
ssh-copy-id hadoop-worker1
ssh-copy-id hadoop-worker2
同样,Worker1和Worker2之间也需要互相信任,因为Hadoop在启动DataNode时可能会在不同节点间进行数据复制操作,节点之间的心跳和数据块复制都需要网络通信。在Worker1上执行:
bash复制ssh-copy-id hadoop-master
ssh-copy-id hadoop-worker1
ssh-copy-id hadoop-worker2
Worker2上同样操作一遍。
验证方法很简单:在Master上执行ssh hadoop-worker1,如果直接进入对方机器的命令行而不用输密码,说明配置成功。注意第一次连接时会提示确认指纹,输入yes回车即可。
3.3 JDK安装:路径别乱写,后面全依赖它
Hadoop本身是用Java写的,所以JDK是必须的。这里有个容易踩的坑:Hadoop的脚本会通过JAVA_HOME环境变量去找Java,如果你把JDK装在了一个奇怪的自定义目录,一定记得把JAVA_HOME配置到Hadoop的配置文件里,否则启动时会报“JAVA_HOME is not set”。
安装步骤(三台机器都执行):
bash复制# 创建软件安装目录(统一路径,方便后续管理)
mkdir -p /usr/local/java
mkdir -p /usr/local/hadoop
# 解压JDK(假设你在/opt下准备好了jdk-8u392-linux-x64.tar.gz)
tar -zxvf /opt/jdk-8u392-linux-x64.tar.gz -C /usr/local/java/
mv /usr/local/java/jdk1.8.0_392 /usr/local/java/java8 # 重命名,去掉版本号,方便后续脚本引用
# 配置环境变量
cat >> /etc/profile <<EOF
export JAVA_HOME=/usr/local/java/java8
export PATH=\$PATH:\$JAVA_HOME/bin
EOF
# 刷新环境变量并验证
source /etc/profile
java -version
一定要确保java -version输出的版本号是1.8.x,如果输出的是其他版本,可能系统自带了openjdk,需要先卸载或者修改PATH顺序。
我这里用了/usr/local/java/java8这个路径,不是为了装X,而是为了让JAVA_HOME路径里不带版本号。这样以后升级JDK时只需要改软链接和环境变量,而不用改所有配置文件。这个习惯在维护真实集群时非常有用。
4. Hadoop安装与配置文件详解:核心中的核心
4.1 解压与目录规划
Hadoop的安装包可以从Apache官网或者清华镜像下载。我用的版本是hadoop-3.3.6.tar.gz。下载完成后:
bash复制# 在Master上解压
tar -zxvf /opt/hadoop-3.3.6.tar.gz -C /usr/local/hadoop/
mv /usr/local/hadoop/hadoop-3.3.6 /usr/local/hadoop/hadoop
# 配置环境变量
cat >> /etc/profile <<EOF
export HADOOP_HOME=/usr/local/hadoop/hadoop
export PATH=\$PATH:\$HADOOP_HOME/bin:\$HADOOP_HOME/sbin
EOF
source /etc/profile
hadoop version
然后需要把整个hadoop目录分发到Worker节点。这里注意一个细节:不要用scp把整个目录传过去后就完了,还要把/etc/profile里的Hadoop相关环境变量在Worker上也配置一遍。如果你图省事用rsync同步整个目录,也要确认目录权限没被搞乱。
从Master向Worker分发Hadoop目录:
bash复制scp -r /usr/local/hadoop/hadoop hadoop-worker1:/usr/local/hadoop/
scp -r /usr/local/hadoop/hadoop hadoop-worker2:/usr/local/hadoop/
分发完成后,还需要在Worker上执行环境变量配置,然后source /etc/profile验证。
4.2 五个核心配置文件详解
Hadoop的配置集中在$HADOOP_HOME/etc/hadoop/目录下。对于完全分布式集群,需要修改的文件有5个:hadoop-env.sh、core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml,以及一个worker列表文件(3.x版本叫workers,2.x版本叫slaves)。
这些文件的配置逻辑是:所有机器上的配置文件必须一致。所以通常在Master上完成所有配置,然后分发到Worker上。
4.2.1 hadoop-env.sh:JAVA_HOME的坑
bash复制vim /usr/local/hadoop/hadoop/etc/hadoop/hadoop-env.sh
找到# export JAVA_HOME=这一行,取消注释并改为:
bash复制export JAVA_HOME=/usr/local/java/java8
很多教程只用环境变量,不在这里配置。但如果Hadoop在启动时没有读到/etc/profile里的JAVA_HOME(比如通过一些不加载profile的方式启动),就会直接报错。所以这里一定写死,多写一行不丢人,能救一条命。
4.2.2 core-site.xml:指定NameNode的地址
xml复制<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop-master:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop/tmp</value>
</property>
</configuration>
fs.defaultFS指定了HDFS的NameNode地址和RPC通信端口。端口9000是默认端口,如果没有特殊要求不用改。关键是hadoop.tmp.dir这个参数,它决定HDFS的元数据(fsimage和edits log)存在哪里。
这里有一个教训:如果你不设置hadoop.tmp.dir,Hadoop会默认使用/tmp/hadoop-${user}作为临时目录。而Linux系统重启后会自动清理/tmp目录下的内容,导致NameNode的元数据全没了,重新格式化又会造成DataNode的namespaceID不一致,集群直接废掉。所以一定自定义这个目录。
4.2.3 hdfs-site.xml:副本数与NameNode目录
xml复制<configuration>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:///usr/local/hadoop/namenode-dir</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///usr/local/hadoop/datanode-dir</value>
</property>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop-master:9868</value>
</property>
</configuration>
dfs.replication这个值我设为2,因为我们有2个DataNode,每个数据块存2份。有些教程会让你设为3,但是如果你只有2个Worker,设了3会因为找不到第3个节点而一直报块副本不足的告警,虽然不会崩溃,但看日志会很膈应。副本数不要超过节点数,这是基本原则。
dfs.namenode.name.dir和dfs.datanode.data.dir分别指定NameNode和DataNode的数据存放路径。注意这里用的是file://前缀,表示本地文件系统。
4.2.4 yarn-site.xml:任务调度与资源管理
xml复制<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop-master</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce_shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>2048</value>
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>2</value>
</property>
</configuration>
yarn-site.xml负责YARN资源调度器。yarn.resourcemanager.hostname指定了ResourceManager运行在哪台机器上,这里设为Master。aux-services配置项里,mapreduce_shuffle是MapReduce任务洗牌阶段所必需的,少了它MR任务跑不起来。后面的memory和cpu配置,可以根据虚拟机的实际资源配置调整,上面这两个值对3GB内存2核的虚拟机来说比较合理。
4.2.5 mapred-site.xml:让MapReduce跑在YARN上
xml复制<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop-master:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop-master:19888</value>
</property>
</configuration>
mapreduce.framework.name设为yarn,表示MapReduce任务提交到YARN上运行,这是Hadoop 2.x以后的标配。如果你的Hadoop还在用类似1.x的老配置方式,建议看一眼版本号。后面的jobhistory配置是历史任务服务器,跑完任务后可以到19888端口查看任务详情,调试很好用。
4.2.6 workers文件:告诉Hadoop谁是Worker
bash复制vim /usr/local/hadoop/hadoop/etc/hadoop/workers
把localhost那行删掉,改为:
code复制hadoop-worker1
hadoop-worker2
workers文件的作用是:当你在Master上执行start-dfs.sh或start-yarn.sh脚本时,脚本会读取这个文件,并逐行登录对应机器启动DataNode和NodeManager进程。所以这个文件只在Master上有用,但为了保持集群配置一致,我通常会把它也复制到Worker上。
4.3 配置文件分发与目录权限
所有配置完成并检查无误后,把hadoop配置目录同步到Worker:
bash复制scp -r /usr/local/hadoop/hadoop/etc/hadoop/* hadoop-worker1:/usr/local/hadoop/hadoop/etc/hadoop/
scp -r /usr/local/hadoop/hadoop/etc/hadoop/* hadoop-worker2:/usr/local/hadoop/hadoop/etc/hadoop/
然后在三台机器上分别创建NameNode和DataNode的数据目录,并确保hadoop用户或者当前用户对这些目录有完全权限:
bash复制# 三台机器都执行
mkdir -p /usr/local/hadoop/namenode-dir
mkdir -p /usr/local/hadoop/datanode-dir
mkdir -p /usr/local/hadoop/tmp
chown -R $USER:$USER /usr/local/hadoop/
如果用的是root用户,最后的chown可以直接跳过,但如果是普通用户(强烈建议),chown是必须的,否则Hadoop在写数据时会出现Permission denied,这类错误特别隐蔽,启动时不一定暴露,等上传文件时才崩溃。
5. 格式化NameNode与集群启动:成败在此一举
5.1 格式化NameNode:只执行一次的命令
在Master上执行:
bash复制hdfs namenode -format
这个命令的作用是初始化NameNode的元数据目录,生成fsimage文件和集群ID(clusterID)。很多人会问,为什么要格式化?简单类比:NameNode是HDFS的“大脑”,它需要一份初始状态的记忆文件来记录整个文件系统的目录结构。格式化就是给这块空白大脑写上一页初始化信息。
极其重要的一点:这个命令只能执行一次。 如果你启动后发现NameNode有问题,想格式化来“重置”,那么同时还要清空所有DataNode的datanode-dir目录,否则会出现clusterID不匹配、DataNode无法注册到NameNode的报错。这类报错通常是“Incompatible clusterIDs”,很多新手被这个坑得欲哭无泪。如果你遇到这个问题,解决办法是:先stop-all.sh停掉集群,然后删除所有节点上namenode-dir和datanode-dir目录的内容,再重新格式化。注意,这会导致HDFS上所有数据丢失,生产环境千万别这么干。
格式化成功的标志是日志末尾出现successfully formatted,并且列出了Storage directory的路径。
5.2 启动HDFS与YARN
在Master上执行以下命令启动HDFS:
bash复制start-dfs.sh
此时脚本会根据workers文件登录到worker1和worker2,分别启动DataNode进程。由于我们配了SSH免密,这个过程中不需要输入密码。启动完成后,可以分别在每台机器上执行jps查看Java进程:
- Master上应该有:NameNode、SecondaryNameNode
- Worker上应该有:DataNode
如果进程不对,就需要看日志了。启动日志在各节点$HADOOP_HOME/logs/目录下,NameNode日志在logs/hadoop-$(whoami)-namenode-hadoop-master.log,DataNode日志类似。这个日志文件非常重要,排障全靠它。
接着启动YARN:
bash复制start-yarn.sh
启动后,Master上应该多出ResourceManager进程,Worker上多出NodeManager进程。此时三台机器的jps输出应该类似这样:
Master:
code复制12345 NameNode
12366 SecondaryNameNode
12390 ResourceManager
Worker1和Worker2:
code复制23456 DataNode
23478 NodeManager
5.3 访问Web UI验证
Hadoop提供了两个Web界面:
- HDFS界面:http://hadoop-master:9870,可以查看NameNode状态、DataNode列表、文件系统使用情况。注意是9870不是50070,Hadoop 3.x改成了9870,2.x才是50070,这个变化让很多人找半天入口。
- YARN界面:http://hadoop-master:8088,可以查看正在运行的任务、资源使用情况、节点列表。
如果这两页面能正常打开,并且DataNode列表里能看到2个活跃节点,说明HDFS已经正常工作了。
5.4 跑一个测试任务验证分布式计算
光有界面还不够,建议上传一个文件并跑一个MapReduce任务来验证整个链条:
bash复制# 创建HDFS目录
hdfs dfs -mkdir -p /test/input
# 创建一个本地测试文件
echo "Hello Hadoop Hadoop HDFS" > /tmp/test.txt
# 上传到HDFS
hdfs dfs -put /tmp/test.txt /test/input/
# 查看文件是否在HDFS上(注意会显示副本数2)
hdfs dfs -ls /test/input
# 跑一个WordCount任务(Hadoop自带的示例jar包)
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.6.jar wordcount /test/input /test/output
# 查看输出结果
hdfs dfs -cat /test/output/part-r-00000
输出里应该能看到“Hadoop 2、Hello 1、HDFS 1”这类计数。如果这个流程能跑通,说明你的完全分布式集群已经可以正常使用了。
6. 常见问题与排查技巧实录
Hadoop搭建过程中,大概率会遇到下面这些异常。我把最典型的问题整理成了一张速查表,每个问题都附上了排查思路和解决办法。
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| jps看不到DataNode进程 | 格式化后没清空DataNode目录,clusterID不一致 | 查看datanode日志,如果报Incompatible clusterID,删除所有节点datanode-dir后重新格式化 |
| 上传文件报“File could only be replicated to 0 nodes” | DataNode没起来或网络不通 | 检查每个节点jps、防火墙、hosts映射、DataNode日志 |
| SSH免密不生效 | hosts文件没配对、私钥权限不对、ssh-copy-id没执行成功 | 检查~/.ssh目录权限,私钥必须是600,authorized_keys必须是700 |
| SecondaryNameNode进程不存在 | 配置里没指定secondary.http-address | 检查hdfs-site.xml,补上dfs.namenode.secondary.http-address |
| yarn任务卡在ACCEPTED状态 | 内存资源不足,NodeManager可用内存太小 | 调整yarn.nodemanager.resource.memory-mb,同时确认各节点内存充足 |
| HistoryServer访问不了 | 没有启动historyserver或端口没开放 | 执行mapred --daemon start historyserver,确认19888端口可访问 |
6.1 DataNode起不来:最经典的clusterID不匹配
我在搭建过程中,第一次格式化后启动,Master的NameNode正常,但Worker的DataNode总是一启动就退出。查日志发现java.io.IOException: Incompatible clusterIDs。原因很简单:我之前格式化过一次NameNode,后来又改了配置重新格式化,导致NameNode生成了新的clusterID,但DataNode的clusterID还是旧的。解决办法就是按前面说的,清空所有节点的数据目录再重新格式化。
这个坑在以后集群扩容时也容易遇到:你新加了一台机器,里面如果残留了旧的数据目录,就可能导致DataNode无法加入集群。所以新节点加入集群前,一定要确保datanode-dir是空目录。
6.2 上传文件报0 nodes:先从防火墙查起
我遇到过一次很诡异的情况:jps显示DataNode都在,但上传文件一直报0 nodes。排查了很久,最后发现是主机上的防火墙没关干净,DataNode和NameNode之间的通信被拦截了,DataNode反复注册不上。另外还有一个可能,就是hosts文件里写的主机名和hostnamectl设置的不一致,导致NameNode通过错误的IP去连接DataNode。
6.3 内存参数调优的临时解决方案
如果虚拟机内存确实紧张,可以在hadoop-env.sh里调整HDFS相关进程的堆内存。默认的HADOOP_HEAPSIZE是1000MB,三台机器的NameNode和ResourceManager各占1G,Worker的DataNode和NodeManager加起来也要2G,再加上操作系统本身的内存占用,3G内存的虚拟机确实很吃紧。可以改成512MB临时跑通:
bash复制export HADOOP_HEAPSIZE=512
export HADOOP_NAMENODE_OPTS="-Xmx512m $HADOOP_NAMENODE_OPTS"
export HADOOP_DATANODE_OPTS="-Xmx512m $HADOOP_DATANODE_OPTS"
7. 集群的启停命令与日常维护
以后每次开机,启动顺序都很重要,混乱的启停顺序虽然不致命,但会浪费你排查问题的时间。
启动集群(在Master上执行):
bash复制start-dfs.sh
start-yarn.sh
mapred --daemon start historyserver
停止集群:
bash复制mapred --daemon stop historyserver
stop-yarn.sh
stop-dfs.sh
其实还有个更粗暴的一键命令:stop-all.sh和start-all.sh,在脚本里会依次调用dfs和yarn的启停。但对于学习阶段,我建议分开执行,这样你能清楚地知道每个脚本做了什么。
另外一个日常维护要点:查看集群状态。HDFS层面可以用hdfs dfsadmin -report查看每个DataNode的存储情况和状态。YARN层面可以在8088页面看到各个NodeManager的资源使用情况和正在运行的Application。
如果跑任务时发现某个NodeManager没启动,不要盲目在Master上重启整个集群,直接SSH到对应节点手动重启:
bash复制ssh hadoop-worker1 "/usr/local/hadoop/hadoop/sbin/yarn-daemon.sh start nodemanager"
单点操作比整体重启更能锻炼你的故障处理能力,也更符合生产环境下的运维习惯。
8. 关于这个集群还能怎么玩
集群搭起来之后,不要急着关掉。我强烈建议接下来做这几件事,可以帮你把“搭起来”变成“用起来”:
-
实验副本数策略:把dfs.replication改成1,上传一个文件,然后手动kill掉一个DataNode节点,再看HDFS页面,观察文件块的状态变化。再改回2,启动节点,观察数据块怎么自动补副本。这个过程能让你直观理解HDFS的容错机制。
-
跑一个真实的数据处理任务:不要只跑WordCount,找一份CSV格式的数据,比如电商订单或者日志数据,用Hive或者Spark SQL去做一些统计。这个过程中你会发现,HDFS只是存储底座,真正要干活还得配合计算框架。
-
给集群加一台节点:完全分布式最大的乐趣就是可以扩展。准备第四台虚拟机,配置好JDK和SSH,把Hadoop目录分发过去,在workers文件里加一行,然后重启集群,看DataNode列表里多出一个节点。这个过程你走一遍,对HDFS的扩容机制就会有非常直观的理解。
根据我做过的项目经验,Hadoop作为入门分布式系统的第一课,它的价值不在于技术本身有多新,而在于它把分布式系统的核心痛点——网络通信、数据冗余、任务调度、资源管理——全部暴露在了你面前。后面你学Zookeeper、Kafka、Flink,会发现很多设计思路都和Hadoop一脉相承。集群搭起来只是起点,之后的实验和折腾才是真正提升的地方。
