1. 为什么每个学大数据的人都绕不开这三种安装模式
先说我自己的经历。第一次接触Hadoop时,我照着网上的教程折腾了整整两天,最后集群没起来,倒是把虚拟机搞崩了三次。问题出在哪?教程东一篇西一篇,有的讲单机版,有的直接上三节点集群,我根本分不清它们之间的区别,也不知道自己当前到底该用哪一种。
后来把三种模式彻底理了一遍才明白,Hadoop的安装配置其实就三条路:本地模式(Local Mode)、伪分布式模式(Pseudo-Distributed Mode)、完全分布式模式(Fully-Distributed Mode)。三者的区别不只是“几台机器”这么简单,而是映射了你的实际需求:是想跑通一个示例验证环境,还是想模拟完整的分布式流程,或者是搭建一个真正能用于开发测试的集群。
这篇内容就是我从零开始配置三种模式的完整记录,包含每一步的配置文件和参数含义,以及我在实验过程中遇到的报错和排查过程。适合刚接触Hadoop、准备做实验或者正在搭开发环境的人参考,不管你是用虚拟机、云服务器还是自己的笔记本,思路都是通用的。
有一点先说清楚:这篇文章里所有的路径、版本号和配置参数,我都以Hadoop 3.x和JDK 1.8的组合为例,这也是目前大多数大数据课程和实验环境采用的主流组合。你用2.x版本时部分配置项名称会有差异,我会在对应位置标注出来。
2. 开始之前必须想明白的三个问题
配置Hadoop之前,先别急着解压安装包。我把身边同学踩过的坑归拢了一下,发现大部分问题都出在下面这三个环节,提前搞定它们能省下大量排查时间。
2.1 JDK版本和Hadoop版本怎么匹配
很多人的第一个坑就是JDK版本不对。Hadoop对JDK的版本要求非常明确,以Hadoop 3.x为例,官方文档标注支持Java 8和Java 11,但实际实验中最稳的是JDK 1.8。我试过用JDK 17跑Hadoop 3.3.x,结果启动NameNode的时候直接报UnsupportedClassVersionError,折腾了半小时查日志才发现是版本问题。
安装完JDK后,第一件事就是在终端里确认版本号:
java -version正常情况下应该输出类似这样的内容:
java version "1.8.0_202" Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)同时需要配置JAVA_HOME环境变量。网上的教程让你改/etc/profile、~/.bashrc都行,我的习惯是写在~/.bashrc里,这样只对当前用户生效,不会影响系统全局环境:
export JAVA_HOME=/usr/local/jdk1.8.0_202 export PATH=$JAVA_HOME/bin:$PATH改完之后执行source ~/.bashrc让它立即生效,再用echo $JAVA_HOME验证一下,能正常输出路径就说明配好了。
2.2 主机名、IP和hosts映射最好提前规划
这一点在做完全分布式模式的时候特别重要,但哪怕只是搭伪分布式,我也建议提前规划好。因为Hadoop内部组件之间通信时用的是主机名,如果主机名解析不对,轻则启动慢,重则节点之间互相找不到对方。
修改主机名用这个命令:
hostnamectl set-hostname hadoop01然后编辑/etc/hosts文件,把IP和主机名的映射关系写进去:
192.168.10.10 hadoop01 192.168.10.11 hadoop02 192.168.10.12 hadoop03注意:不要用
127.0.0.1或者localhost来代替集群中其他节点的IP,否则分布式模式下NameNode和DataNode之间的心跳通信会出问题。我见过有人直接在hosts里写127.0.0.1 hadoop01,结果三台机器互相访问的时候全指向本机了,DataNode一直注册不上。
2.3 SSH免密登录要提前配好
Hadoop的守护进程启动时,需要远程到各个节点去拉起来,这个过程就是靠SSH来做的。如果不配置免密,每次启动集群都要输一堆密码,而且脚本自动化执行的时候根本没法输入,所以免密登录是必需项。
最简单的验证方法是先对当前用户生成密钥:
ssh-keygen -t rsa -P ''一路回车,-P ''的意思是不设置密码短语,生成后直接测试:
ssh localhost如果不需要输密码就能登录,说明本机免密已经生效。做成完全分布式的时候,还需要把公钥分发到各台机器,具体操作我在后面完全分布式的部分会详细讲。
3. 本地模式:十分钟验证Hadoop环境能跑起来
本地模式是Hadoop最简单的一种部署方式,它的特点是:所有进程都在同一个Java虚拟机里运行,不启动HDFS,不启动YARN,也不涉及任何分布式文件系统和资源调度。它存在的意义就是让你快速验证Hadoop环境是否安装正确、依赖是否完整。
3.1 本地模式的原理和适用场景
很多人不理解为什么要有本地模式,觉得“不就是能跑个wordcount吗,有什么用”。这种想法不太对。本地模式的价值在于,它是一个最底层的环境自检:如果连本地模式都跑不起来,那伪分布式和完全分布式就更不用谈了。
本地模式下,Hadoop会使用本地文件系统作为输入输出,没有NameNode和DataNode这些角色的概念。比如在本地模式运行一个WordCount示例,大致流程是:MapReduce框架在当前JVM里读本地文件,经过Map阶段和Reduce阶段,再把结果写到本地目录。整个过程可以理解为“用Hadoop的API在本地模拟了一次MapReduce计算”,因为不涉及跨进程和跨节点调度,所以速度非常快,适合做功能验证。
3.2 解压和配置的完整流程
首先,把下载好的Hadoop安装包解压到你想要的目录:
tar -zxvf hadoop-3.3.4.tar.gz -C /usr/local/解压后进入Hadoop目录,你会看到一系列子目录。第一次接触的人可能有点懵,我简单列一下最关键的几个:
| 目录 | 作用 |
|---|---|
| bin | Hadoop命令存放位置,后续所有操作都要用到这里面的脚本 |
| etc/hadoop | 所有配置文件所在目录,配置工作主要就是改这里 |
| sbin | 守护进程启动和停止脚本,比如start-dfs.sh |
| share | 自带的示例包和jar包,WordCount示例就在这里 |
接着需要修改etc/hadoop/hadoop-env.sh文件,把JDK路径告诉Hadoop,因为Hadoop启动脚本需要找到Java:
export JAVA_HOME=/usr/local/jdk1.8.0_202修改完这个之后,检查一下Hadoop的版本号,看看安装是否正常:
cd /usr/local/hadoop-3.3.4 bin/hadoop version如果输出了类似下面的内容,说明Hadoop本身已经能正常用Java运行了:
Hadoop 3.3.4 Java 1.8.0_202 ...3.3 跑通官方自带的WordCount示例验证环境
官方自带的示例包在share/hadoop/mapreduce/目录下,是一个名为hadoop-mapreduce-examples-3.3.4.jar的jar包。我们直接在本地模式跑一下WordCount,作为环境验证的标准动作。
先在Hadoop目录下创建一个临时输入文件,随便写几行内容:
mkdir input echo "hello hadoop hello world" > input/test.txt然后执行:
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.4.jar wordcount input output执行过程中会打印一堆日志,看到类似于Map-Reduce Framework的输出信息时,说明任务正在走MapReduce流程。执行完成后,查看输出文件:
cat output/part-r-00000如果正常输出:
hadoop 1 hello 2 world 1就说明本地模式完全没问题了。
这里有一个我踩过的细节:第二次运行wordcount之前,必须先把output目录删掉,否则会报Output directory output already exists错误。这是因为Hadoop的MapReduce框架出于安全考虑,不允许不经确认就覆盖已有输出目录。实验的时候每次重跑都要rm -rf output,这个动作要养成肌肉记忆。
4. 伪分布式模式:一台机器上模拟出完整集群
本地模式跑通之后,下一步就是伪分布式。伪分布式的核心价值在于,它让HDFS、YARN、MapReduce这些分布式组件都以真实进程的形式在你本机上运行,虽然都挤在一台机器里,但角色之间的通信、调度逻辑和完全分布式是一致的。对于学习Hadoop的运行机制来说,伪分布式是最划算的投入。
4.1 伪分布式和本地模式的关键差异
伪分布式模式下,格局发生了变化:
- HDFS:启动了NameNode和DataNode两个进程,一个负责元数据管理,一个负责实际数据块存储
- YARN:启动了ResourceManager和NodeManager进程,开始有资源调度和任务分配的概念
- 分布式文件系统:输入输出的存储介质不再是本地文件系统,而是HDFS
graph TD A[本地模式] --> B[进程全在一个JVM] A --> C[没有HDFS/YARN] D[伪分布式] --> E[每个守护进程独立JVM] D --> F[有HDFS/YARN] D --> G[部署在一台机器上]4.2 核心配置文件逐个拆解
伪分布式模式需要修改两组核心配置文件:core-site.xml和hdfs-site.xml。网上教程往往一句话“把如下内容粘贴进去”就完了,但如果你不知道每个参数的含义,后面出了问题的排查成本非常高。我把参数拆开讲。
第一个是etc/hadoop/core-site.xml,它的作用是指定HDFS的NameNode地址,以及临时文件目录。
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>file:///usr/local/hadoop-3.3.4/tmp</value> </property> </configuration>fs.defaultFS的值是hdfs://localhost:9000,意味着所有HDFS操作默认连接到本机9000端口上的NameNode。hadoop.tmp.dir参数指定元数据和数据块的存储根目录。注意这个参数默认值是/tmp/hadoop-${user.name},而系统/tmp目录重启后在大多数Linux发行版中会被清空,这就可能导致NameNode格式化后的元数据丢失,所以务必改到自己的Hadoop安装目录下。
第二个是etc/hadoop/hdfs-site.xml,主要配置数据块副本数量。伪分布式因为只有一个DataNode,副本数只能设为1,如果保持默认的3,DataNode会一直尝试复制副本,报出一堆健康警告。
<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>4.3 格式化NameNode这一步不能省
配置改完之后,需要执行一次NameNode格式化。这个操作的作用是初始化文件系统元数据存储结构,相当于给磁盘文件系统做一次格式化。以后的每次启动都是基于这次格式化产生的结果。
bin/hdfs namenode -format执行成功的标志是日志中出现了类似successfully formatted的提示,以及在/usr/local/hadoop-3.3.4/tmp/dfs/name/current目录下生成了VERSION、edits_0000000000000000000、fsimage_0000000000000000000等文件。
这是我踩得最惨的坑:Hadoop只能格式化一次,或者更准确地说,重复格式化会让NameNode生成的clusterID和DataNode已存储的clusterID不一致,导致DataNode启动后无法向NameNode注册。实验中如果你必须重新格式化,一定要先删掉
tmp目录下的所有内容,让NameNode和DataNode在相同的clusterID下重新初始化,否则你就得在日志里看到我见过的那句Incompatible clusterIDs了。
4.4 启动HDFS并验证进程状态
格式化完成后就可以启动HDFS了:
sbin/start-dfs.sh在启动过程中,会要求你输入SSH密码,如果你提前配置了ssh localhost免密,就会直接跳过。启动完成后,用JPS命令检查Java进程:
jps正常情况下应该看到四个进程:
| 进程名 | 作用 |
|---|---|
| NameNode | HDFS的命名节点,管理文件系统的命名空间 |
| DataNode | 数据节点,存储实际数据块 |
| SecondaryNameNode | 辅助NameNode合并编辑日志 |
| Jps | JPS命令自身,不用管它 |
如果少了其中任何一个,优先去Hadoop根目录下的logs/目录看对应日志文件。日志是最好的排错信息源,我在后面的排错部分会再展开。
4.5 验证HDFS读写和Web UI
启动后,在HDFS上创建一个目录,再上传一个文件测试读写:
bin/hdfs dfs -mkdir -p /user/root/input bin/hdfs dfs -put input/test.txt /user/root/input/ bin/hdfs dfs -cat /user/root/input/test.txt能正常显示文件内容,就说明HDFS的读写链路是通的。
另外,NameNode提供了一个Web UI界面,浏览器访问:
http://localhost:9870这是Hadoop 3.x的默认端口,2.x版本是50070。界面上能看到集群的健康状态、DataNode在线列表和HDFS存储使用情况。一个容易出现的坑是端口访问不了,如果你是在云服务器或者虚拟机上配置的,检查一下防火墙和安全组有没有放通9870端口。
5. 完全分布式模式:三节点集群从规划到启动的完整记录
完全分布式才是Hadoop“分布式”的真正体现:多台机器、各自独立的进程、通过网络通信协同工作。实验环境和生产环境大多采用这种模式,所以这一部分值得仔细过一遍。
5.1 节点规划:主节点和从节点怎么分工
我的实验环境是三台虚拟机,操作系统都是CentOS 7.9。规划如下:
| 节点 | 主机名 | 角色 |
|---|---|---|
| 主节点 | hadoop01 | NameNode、ResourceManager |
| 从节点1 | hadoop02 | DataNode、NodeManager |
| 从节点2 | hadoop03 | DataNode、NodeManager |
为什么这样规划?完全分布式的核心角色中,NameNode负责管理整个文件系统的命名空间,ResourceManager负责YARN的资源管理和作业调度,这两个角色对机器的资源要求较高,放在主节点。DataNode负责数据块存储,NodeManager负责具体计算任务的执行,它们是真正干活的,可以分布在多台从节点上。
如果你还想加一个SecondaryNameNode角色,我记得常见的做法是把它放到另一台机器上,避免和NameNode同机,这样可以分散单点压力。实验环境里如果不加也不影响核心功能验证。
5.2 三台机器共用的环境准备
三台机器都需要准备一份相同的JDK和Hadoop安装环境。快手做法是在一台机器上配置好,然后通过SCP分发过去:
scp -r /usr/local/jdk1.8.0_202 root@hadoop02:/usr/local/ scp -r /usr/local/hadoop-3.3.4 root@hadoop02:/usr/local/别忘了修改每台机器的/etc/hostname和/etc/hosts。还有hadoop-env.sh里JAVA_HOME的路径,三台机器要保持一致。
5.3 完全分布式的五个核心配置文件
相比伪分布式,完全分布式需要配置的文件数量更多。我按表格列出每个文件的职责,再逐个说明关键参数:
| 配置文件 | 作用 |
|---|---|
| core-site.xml | HDFS地址、临时目录等核心配置 |
| hdfs-site.xml | 副本数、NameNode和SecondaryNameNode地址 |
| yarn-site.xml | YARN资源调度相关配置 |
| mapred-site.xml | MapReduce运行框架配置 |
| workers | 声明哪些主机是DataNode/NodeManager |
core-site.xml,配置在主节点上:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop01:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>file:///usr/local/hadoop-3.3.4/tmp</value> </property> </configuration>注意这里fs.defaultFS的值由localhost换成了主节点的主机名hadoop01,因为从节点需要通过主机名找到NameNode,用localhost的话从节点就会尝试连自己,导致整个集群完全无法通信。
hdfs-site.xml:
<configuration> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.namenode.secondary.http-address</name> <value>hadoop02:50090</value> </property> </configuration>副本数设为2而不是3,这是实验环境下的常见选择。因为只有三个节点,如果设3,三个DataNode各存一份也没有问题,但从节省空间的角度没必要。设为2表示除了本节点之外再找一个节点存一份副本,在节点故障时能恢复数据即可。
yarn-site.xml:
<configuration> <property> <name>yarn.resourcemanager.hostname</name> <value>hadoop01</value> </property> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration>第一个参数指定ResourceManager跑在哪台机器上,第二个参数mapreduce_shuffle是MapReduce任务执行时的辅助服务,属于YARN运行MapReduce作业的必要配置。很多教程会漏掉第二项,漏掉之后作业提交到YARN时会在Shuffle阶段报错。
mapred-site.xml:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>这个参数告诉MapReduce作业的运行框架是YARN,而不是内置的本地框架。漏了它的话作业不会提交到集群上执行。
workers文件(Hadoop 3.x叫workers,2.x叫slaves):
hadoop02 hadoop03这个文件的作用是声明哪些节点是Worker节点,启动脚本会根据内容去远程拉起DataNode和NodeManager。注意文件里每行一个主机名,不能有空格或者多余字符。
5.4 把配置同步到所有节点
所有配置都在主节点上改好之后,用SCP把整个Hadoop配置目录同步到从节点:
scp -r /usr/local/hadoop-3.3.4/etc/hadoop/* root@hadoop02:/usr/local/hadoop-3.3.4/etc/hadoop/ scp -r /usr/local/hadoop-3.3.4/etc/hadoop/* root@hadoop03:/usr/local/hadoop-3.3.4/etc/hadoop/从节点上不需要单独改配置,因为核心配置里写的是主节点的主机名,从节点启动时会自动去连接主节点。
5.5 SSH免密登录的完整配置动作
完全分布式模式下,主节点需要无密码登录到所有从节点,才能远程启动守护进程。前置条件是把主节点的公钥写到从节点的authorized_keys文件里:
# 在主节点上执行 ssh-keygen -t rsa -P '' ssh-copy-id root@hadoop01 ssh-copy-id root@hadoop02 ssh-copy-id root@hadoop03然后逐台验证:
ssh hadoop01 ssh hadoop02 ssh hadoop03能不打密码直接进去就说明免密配置成功。
5.6 格式化NameNode并启动集群
完全分布式模式下,格式化操作只需要在主节点上执行一次:
bin/hdfs namenode -format格式化完成后启动HDFS和YARN:
sbin/start-dfs.sh sbin/start-yarn.sh启动完成后,在主节点上执行jps,应该看到:
NameNode ResourceManager在从节点上执行jps,应该看到:
DataNode NodeManager再到Web UI上检查集群状态。HDFS的Web UI和伪分布式一样是http://hadoop01:9870,YARN的Web UI是http://hadoop01:8088。YARN的界面上能看到NodeManager列表,正常情况下应该有两台节点在线。
5.7 提交一个真正的分布式作业
在生成环境中验证集群是否工作正常,最直接的方式是提交一个作业到集群上跑。先在HDFS上建目录、传文件:
bin/hdfs dfs -mkdir -p /user/root/input bin/hdfs dfs -put input/test.txt /user/root/input/然后提交WordCount:
bin/yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.4.jar wordcount /user/root/input /user/root/output执行完之后用命令检查结果:
bin/hdfs dfs -cat /user/root/output/part-r-00000到这一步,完全分布式集群就算真正搭建完成并且能跑作业了。
6. 三台机器搭建过程中最容易翻车的五个问题
配置过程很少是一帆风顺的,我把自己实验中遇到过的问题列出来,这些问题有一定的共性,提前了解能省下不少排查时间。
6.1 DataNode进程起不来:clusterID不一致
现象:主节点NameNode正常启动,但从节点的DataNode进程反复挂掉,日志里报Incompatible clusterIDs或者java.io.IOException: NameNode is not formatted。
原因:重复格式化了NameNode,导致NameNode生成了新的clusterID,而DataNode数据目录里存的还是旧的clusterID。
解决方式:在所有节点上删除临时目录下的DFS数据,然后回到主节点重新格式化:
rm -rf /usr/local/hadoop-3.3.4/tmp/dfs/ bin/hdfs namenode -format格式化后同步到所有从节点,重启start-dfs.sh。这一步做完之后我特地对比了一下tmp/dfs/name/current/VERSION和tmp/dfs/data/current/VERSION里的clusterID,确认一致后才启动,此后DataNode就没有再掉线过。
6.2 虚拟内存超出限制导致Container被杀死
现象:作业提交到YARN后,Map或Reduce任务反复失败,日志里频繁出现Container is running beyond virtual memory limits之类的报错。
原因:默认情况下,每个NodeManager容器能被分配的内存有限,虚拟内存超过阈值就会被杀死。这在虚拟机环境下非常常见,因为虚拟机的内存本来就小。
解决方式:打开YARN的yarn-site.xml,把虚拟内存比调大或者直接关掉这个检查:
<property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property>如果希望更精确地限制,也可以同时调整yarn.nodemanager.vmem-pmem-ratio的值为4或更高。关掉检查实测最省心,前提是集群只用于实验环境。
6.3 SSH免密配置好依然要输密码
现象:主节点SSH到从节点仍然要求输密码。
原因:SSH对目录和文件的权限要求非常严格,.ssh目录的权限必须为700,authorized_keys文件的权限必须为600,权限过宽会导致SSH拒绝读取公钥。
解决方式:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys另一个容易被忽略的点是,你当前登录的用户必须和生成密钥的用户一致。比如用root生成密钥,就要确保远程连接时用的也是root用户。
6.4 端口不通:Web UI无法访问
现象:在宿主机浏览器上访问http://hadoop01:9870,页面一直打不开,但节点内部访问正常。
原因:最常见的是防火墙未放行端口,或者是云服务器的安全组配置没加规则。
解决方式:
systemctl stop firewalld systemctl disable firewalld如果是在云服务器上,还需在控制台的安全组中添加9870和8088端口的入站规则。这一步容易被忽略,但实验环境对安全性要求不高的情况下,直接关闭防火墙是最快的方法。
6.5 主节点执行start-dfs.sh后从节点没有任何反应
现象:主节点上执行start-dfs.sh,只启动了本机的NameNode和DataNode,从节点上什么进程都没起。
原因:workers文件配置有问题,或者主节点没有配置到从节点的SSH免密。
解决方式:首先确认workers文件里的内容,注意文件名在Hadoop 3.x是workers,在2.x是slaves,如果你改了Hadoop版本却沿用旧教程,很可能就是在改一个不再起作用的文件。然后验证SSH免密:ssh hadoop02,如果无法免密进入,重新执行ssh-copy-id。
另外一个容易犯的错误是workers文件里包含hadoop01主节点自身,如果你希望主节点不启动DataNode,就不要把它写进去。
7. 三种模式里我在实际配置中的选择建议
站在实验角度把三种模式都过了一遍的人,最后多半会回到一个问题上:实际场景中我应该选哪种模式?
我的建议很简单。如果你只是验证Hadoop安装成功没有,本地模式就够了,五分钟跑完一个WordCount,不需要处理任何配置文件的复杂度;如果你想学习HDFS的读写流程、YARN的调度逻辑,或者准备做后续的HBase、Hive集成实验,伪分布式是最合适的,因为单机就能模拟出完整链路,排错成本也低;如果你想模拟真实的集群环境,或者需要跑多个节点的实验,比如MapReduce的分布式计算效果验证、HDFS副本机制观察,完全分布式才值得你花时间搭一遍。
我见过不少同学一上来就搭三节点集群,结果配置了三天毫无进展,最后回头先把伪分布式摸透了,再回来看完全分布式就觉得豁然开朗。这背后的原因是分布式系统涉及的角色多、网络通信链路长,如果对单机版运行机制不理解,多机环境的问题会让你根本不知道从哪个日志开始看起。
就我自己而言,三台虚拟机的配置目前依然保留着,虽然实验已经结束,但后续再做Spark、Flume或者HBase的集成实验时,直接在这个集群上扩展就行,不用一切从零开始。这也是我建议你把完全分布式搭好的原因——它不只是这周实验的交付物,更是后面整个大数据学习周期的底层平台。