1. 为什么还要聊 Hadoop 2.7.6 这个“老版本”
1.1 一个绕不开的现实场景
现在打开任何一个技术社区,讨论大数据框架的内容几乎被 Spark、Flink、Doris、Iceberg 这些新面孔占满了。Hadoop 看起来像是上个时代的产物,MapReduce 更是被很多人当成“历史遗迹”。但如果你真的在传统行业待过,比如制造、能源、交通、医疗信息化这些领域,你会发现一个很尴尬的事实:大量已经投产的数据平台,底层跑的还是 Hadoop 2.7.x 这一代。原因不复杂——这些系统上线时间早,业务逻辑深度绑定 HDFS 和 YARN,迁移成本高到没人愿意动,只要还能跑,就没人去碰它。
所以“Hadoop 2.7.6 集群部署搭建”这个题目,放到今天依然有非常实际的价值。它不是一个怀旧话题,而是一个存量维护和新人接手的刚需技能。你可能是刚入职一家公司,接手了一套跑了五六年的离线数仓;也可能是实验室里有一批旧机器,导师让你先把 Hadoop 环境搭起来跑通流程。不管是哪种情况,你都需要一套能落地、能排错、能复现的部署方案。
这篇文章面向的就是这类读者:对 Linux 有基本操作能力,知道什么是 SSH、什么是配置文件,但没完整搭过一个多节点 Hadoop 集群。我会从零开始,把每一步的意图、参数含义、容易踩的坑都讲清楚。搭完之后你会得到一个可以正常提交 MapReduce 任务、能在 YARN 上看到任务执行状态的最小可用集群。
1.2 先搞清楚 Hadoop 2.7.6 的架构骨架
在动手之前,必须先把架构理清楚,否则后面配置文件里一堆-site.xml你会完全不知道在改什么。Hadoop 2.x 的核心变化是引入了 YARN,把资源调度和计算模型拆开了。一个标准集群包含两类角色:
- HDFS 相关进程:NameNode(管理文件系统元数据)、DataNode(实际存数据块)、SecondaryNameNode(定期合并元数据镜像,注意它不是 NameNode 的热备)。
- YARN 相关进程:ResourceManager(全局资源调度)、NodeManager(单节点资源管理)、JobHistoryServer(记录已完成任务的历史信息)。
一个最小可用的分布式集群,至少需要三台机器:一台做 Master(跑 NameNode 和 ResourceManager),两台做 Slave(跑 DataNode 和 NodeManager)。如果资源紧张,两台也能跑,但三台是更接近生产的最小拓扑,能让你真正体会到分布式环境下的通信和调度问题。
注意:SecondaryNameNode 和 NameNode 不要放在同一台机器上,虽然技术上可以,但合并元数据时会消耗大量内存和 IO,放在一起容易把 NameNode 拖垮。这是很多教程里不会强调的细节。
1.3 部署前的环境规划清单
我习惯在动手前先列一张规划表,把每台机器的角色、IP、主机名定死,后面所有配置都照着这张表来,避免改到一半忘了哪台是哪台。下面是我常用的一套规划模板,你可以直接套用:
| 主机名 | IP 地址 | 角色 | 内存建议 | 磁盘建议 |
|---|---|---|---|---|
| master | 192.168.1.100 | NameNode、ResourceManager、JobHistoryServer | 4GB+ | 50GB+ |
| slave1 | 192.168.1.101 | DataNode、NodeManager、SecondaryNameNode | 2GB+ | 50GB+ |
| slave2 | 192.168.1.102 | DataNode、NodeManager | 2GB+ | 50GB+ |
内存这块我要多说一句。Hadoop 2.7.6 默认的 JVM 堆配置偏保守,NameNode 默认只有 1000MB,在小集群里勉强够用,但如果你后面要存几十万个文件,元数据会把堆撑爆。建议在hadoop-env.sh里把 NameNode 的堆调到 2GB 以上,具体数值根据你的文件数量估算——经验值是每 100 万个文件块大约需要 1GB 堆内存。
2. 系统层面的准备工作
2.1 主机名与 hosts 映射
很多人搭集群第一步就翻车,问题往往出在主机名解析上。Hadoop 各节点之间通信大量依赖主机名,如果 DNS 解析不稳定或者 hosts 没配好,会出现“能 ping 通 IP 但服务连不上”的诡异现象。
操作很直接,在每台机器上执行:
hostnamectl set-hostname master然后编辑/etc/hosts,三台机器都要加上完整的映射:
192.168.1.100 master 192.168.1.101 slave1 192.168.1.102 slave2改完之后用hostname命令确认当前主机名,再用ping slave1测试解析是否正常。这里有个坑:有些系统的/etc/hosts里默认有一行127.0.0.1 localhost,如果你把主机名也映射到 127.0.0.1,会导致节点间通信走回环地址,集群直接废掉。检查一下,确保主机名映射的是真实的内网 IP。
2.2 SSH 免密登录配置
Hadoop 的启动脚本依赖 SSH 在各节点之间执行命令,如果不配免密,每次启动都要输密码,脚本会直接卡死。配置逻辑是:在 master 上生成密钥对,然后把公钥分发到所有节点(包括 master 自己)。
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa ssh-copy-id master ssh-copy-id slave1 ssh-copy-id slave2验证方式是直接ssh slave1,如果能不输密码进去就说明成功了。这里有个细节:ssh-copy-id会把公钥追加到目标机器的~/.ssh/authorized_keys,如果目标机器没有这个文件它会自动创建,权限也会设好。但如果你手动复制公钥,一定要确保authorized_keys的权限是 600,.ssh目录是 700,否则 SSH 会拒绝使用这个密钥,而且报错信息很隐晦,只会在日志里写“Authentication refused”。
实操心得:配置免密的时候,建议把 master 到所有 slave 的免密都配好,同时 slave 之间也互相配一下。虽然标准部署里 slave 之间不需要免密,但后面如果你要用
start-dfs.sh这种脚本批量操作,或者做数据均衡,slave 之间的通信会省很多事。
2.3 JDK 安装与环境变量
Hadoop 2.7.6 对 JDK 版本有明确要求:必须是 JDK 7 或 JDK 8,JDK 11 及以上会直接报错。我推荐用 JDK 8,兼容性最好。安装方式看你的系统包管理,用yum install java-1.8.0-openjdk-devel或者手动解压 tar 包都行。
安装完之后配置环境变量,编辑/etc/profile,加上:
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk export HADOOP_HOME=/opt/hadoop-2.7.6 export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbinsource /etc/profile之后用java -version确认。这里要注意,JAVA_HOME的路径一定要写对,后面 Hadoop 的配置文件里还会引用这个变量,如果路径错了,启动时会出现“JAVA_HOME is not set”的报错,但实际上是设了的,只是路径不对。
2.4 关闭防火墙与 SELinux
这一步在测试环境里是常规操作,但我要强调一下:生产环境不要直接关防火墙,而是应该开放对应端口。测试环境为了省事可以关掉:
systemctl stop firewalld systemctl disable firewalld setenforce 0SELinux 的配置文件在/etc/selinux/config,把SELINUX=enforcing改成SELINUX=disabled,否则重启后又会生效。Hadoop 用到的端口很多,NameNode 的 8020、ResourceManager 的 8032、JobHistoryServer 的 10020 等等,如果不想关防火墙,至少要把这些端口放行。
3. Hadoop 核心配置逐项拆解
3.1 解压安装与目录结构说明
把下载好的hadoop-2.7.6.tar.gz解压到/opt下,然后重命名或者建软链接。我习惯保留版本号目录,再建一个hadoop软链接指向它,这样以后升级版本只需要改软链接,环境变量不用动。
tar -zxvf hadoop-2.7.6.tar.gz -C /opt/ ln -s /opt/hadoop-2.7.6 /opt/hadoop解压后你会看到几个关键目录:bin放客户端命令,sbin放启动脚本,etc/hadoop放所有配置文件,share放 jar 包。后面我们改的配置文件全在etc/hadoop下面。
3.2 core-site.xml:定义文件系统入口
这个文件的核心作用是告诉 Hadoop“默认的文件系统是什么”。配置项很少,但每一个都关键:
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://master:8020</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/hadoop-2.7.6/tmp</value> </property> </configuration>fs.defaultFS指定了 NameNode 的地址和端口,所有客户端提交任务时都通过这个地址找 NameNode。端口 8020 是 2.x 的默认值,有些旧版本用 9000,两者不能混用,客户端和服务端必须一致。
hadoop.tmp.dir是 Hadoop 的临时目录,默认在/tmp下面。这是个巨大的坑——很多系统重启时会清理/tmp,导致 NameNode 的元数据被删,集群直接起不来。所以一定要改到一个不会被自动清理的路径,并且确保这个目录在所有节点上都存在且权限正确。
3.3 hdfs-site.xml:副本数与数据目录
HDFS 相关的配置都在这里。最核心的两个参数是副本因子和数据目录:
<configuration> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/opt/hadoop-2.7.6/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/opt/hadoop-2.7.6/data/datanode</value> </property> <property> <name>dfs.namenode.secondary.http-address</name> <value>slave1:50090</value> </property> </configuration>副本因子默认是 3,但如果你只有两台 DataNode,设成 3 会导致永远有副本处于“欠复制”状态,虽然不影响使用,但 NameNode 的 Web 界面会一直报警告。所以两台 DataNode 就设成 2,三台以上可以设 3。
dfs.namenode.name.dir和dfs.datanode.data.dir分别指定 NameNode 和 DataNode 的数据存储路径。这两个目录不要放在同一个磁盘上,如果条件允许,NameNode 的目录最好放在独立的盘上,因为元数据的写入对 IO 延迟很敏感。
3.4 yarn-site.xml:资源调度配置
YARN 的配置直接决定了你的任务能跑多快、能跑多少。核心参数如下:
<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.resourcemanager.hostname</name> <value>master</value> </property> <property> <name>yarn.nodemanager.resource.memory-mb</name> <value>2048</value> </property> <property> <name>yarn.scheduler.minimum-allocation-mb</name> <value>512</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property> </configuration>yarn.nodemanager.resource.memory-mb是每个 NodeManager 能分配给容器的总内存,默认是 8192MB,但如果你机器只有 4GB 内存,这个值必须调小,否则 NodeManager 启动时会报“物理内存不足”。我一般设成机器实际内存的 70% 左右,留一部分给系统和其他进程。
yarn.nodemanager.vmem-check-enabled这个参数我强烈建议设成 false。YARN 默认会检查虚拟内存,但很多 Java 程序的虚拟内存占用远大于物理内存,导致任务被无故杀掉,报错信息是“Container killed by YARN for exceeding virtual memory limits”。关掉这个检查能避免大量莫名其妙的失败。
3.5 mapred-site.xml:指定计算框架
这个文件默认不存在,需要从模板复制:
cp mapred-site.xml.template mapred-site.xml然后配置:
<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <property> <name>mapreduce.jobhistory.address</name> <value>master:10020</value> </property> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>master:19888</value> </property> </configuration>mapreduce.framework.name设成yarn表示用 YARN 来调度 MapReduce 任务,这是 2.x 的标准模式。如果设成local,任务会在本地跑,不走集群,那就失去分布式部署的意义了。
3.6 slaves 文件与分发配置
在 master 的etc/hadoop目录下有个slaves文件,里面列出所有 DataNode 和 NodeManager 的主机名:
slave1 slave2这个文件决定了start-dfs.sh和start-yarn.sh会在哪些机器上启动从节点进程。注意 master 自己如果也要做 DataNode,就把 master 也加进去,但通常不建议这么做,Master 节点应该专注于元数据和调度。
配置改完之后,用scp把整个 Hadoop 目录分发到所有 slave 节点:
scp -r /opt/hadoop-2.7.6 slave1:/opt/ scp -r /opt/hadoop-2.7.6 slave2:/opt/分发之后记得在 slave 上也建好软链接和环境变量,或者直接把/etc/profile也同步过去。
4. 集群启动与验证实操
4.1 格式化 NameNode 的正确姿势
第一次启动前必须格式化 NameNode,命令是:
hdfs namenode -format这个命令会创建元数据目录并生成初始的 fsimage。我要重点提醒:格式化只能执行一次。如果你后面改了配置想重新格式化,必须先删掉所有节点的data目录和tmp目录,否则会导致 NameNode 和 DataNode 的 clusterID 不一致,DataNode 启动后会拒绝连接,报错“Incompatible clusterIDs”。
格式化成功的标志是看到“Storage directory ... has been successfully formatted”和“Exiting with status 0”。如果看到“Re-format filesystem”的警告,说明你之前格式化过,这时候要么确认是否真的要重新格式化,要么直接 Ctrl+C 退出。
4.2 启动 HDFS 与 YARN
启动顺序有讲究:先起 HDFS,再起 YARN。因为 YARN 的 NodeManager 在启动时会向 NameNode 汇报本地可用的数据块信息,如果 HDFS 没起来,NodeManager 会报错。
start-dfs.sh start-yarn.sh mr-jobhistory-daemon.sh start historyserver启动完成后,在 master 上执行jps,应该看到 NameNode、ResourceManager、JobHistoryServer;在 slave 上执行jps,应该看到 DataNode、NodeManager,slave1 上还应该有 SecondaryNameNode。
如果某个进程没起来,第一件事是去看日志。日志在$HADOOP_HOME/logs下面,文件名格式是hadoop-<用户名>-<进程名>-<主机名>.log。常见的启动失败原因包括:JAVA_HOME 配错、端口被占用、目录权限不对、hosts 解析失败。
4.3 Web 界面验证与常见异常
Hadoop 2.7.6 提供了几个 Web 界面,是验证集群状态最直观的方式:
| 界面 | 地址 | 用途 |
|---|---|---|
| HDFS 状态 | http://master:50070 | 查看 DataNode 列表、容量、文件系统状态 |
| YARN 状态 | http://master:8088 | 查看集群资源、运行中任务、队列信息 |
| JobHistory | http://master:19888 | 查看已完成任务的详细日志和计数器 |
打开 HDFS 界面,重点看“Live Nodes”是不是等于你的 DataNode 数量。如果少了,说明有 DataNode 没连上 NameNode,去对应机器上看日志。如果看到“Dead Nodes”,说明之前连上过但后来断了,通常是网络抖动或者进程被杀了。
YARN 界面里看“Active Nodes”,应该等于 NodeManager 的数量。如果某个节点显示“Unhealthy”,把鼠标悬停在上面会看到原因,常见的是磁盘空间不足或者内存超限。
4.4 跑一个 MapReduce 任务验证
光看进程起来还不够,得实际跑一个任务才能确认整条链路是通的。Hadoop 自带了一个 wordcount 示例:
hdfs dfs -mkdir -p /test/input hdfs dfs -put $HADOOP_HOME/etc/hadoop/*.xml /test/input hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.6.jar wordcount /test/input /test/output任务提交后,在 YARN 界面上能看到一个 application 在跑,状态从 ACCEPTED 变成 RUNNING,最后变成 FINISHED。跑完之后用hdfs dfs -cat /test/output/part-r-00000看结果,应该能看到各个 XML 文件里单词的计数。
如果任务卡在 ACCEPTED 不动,通常是资源不够——检查yarn.nodemanager.resource.memory-mb和yarn.scheduler.minimum-allocation-mb的配置,确保有足够的资源分配给容器。如果任务失败,去 JobHistory 界面看日志,或者直接在 YARN 界面上点进 application 看详细报错。
5. 踩坑记录与排查手册
5.1 启动失败类问题速查
下面这张表是我这些年搭集群遇到的高频问题,按现象、原因、解决方式整理,方便你直接对照排查:
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| NameNode 启动后立即退出 | 端口 8020 被占用 | `netstat -tlnp |
| DataNode 启动报 clusterID 不一致 | 重复格式化或目录残留 | 删除所有节点的 data 和 tmp 目录,重新格式化 |
| NodeManager 启动报内存不足 | 配置的内存超过物理内存 | 调小yarn.nodemanager.resource.memory-mb |
| Web 界面打不开 | 防火墙未关或端口未放行 | 检查 firewalld 状态和端口监听 |
| 任务一直卡在 ACCEPTED | 资源不足或调度器配置问题 | 检查 YARN 可用资源和最小分配内存 |
| SSH 免密不生效 | 权限不对或 hosts 解析问题 | 检查 .ssh 目录权限和 /etc/hosts |
5.2 那些文档里不会写的经验
第一个经验是关于日志的。Hadoop 的日志默认按天滚动,但如果你在调试阶段频繁重启,日志会迅速膨胀。我习惯在调试时把log4j.properties里的日志级别调到 DEBUG,但只针对特定包,比如log4j.logger.org.apache.hadoop.hdfs=DEBUG,这样既能拿到详细信息,又不会把整个日志淹没。
第二个经验是关于时间同步的。Hadoop 对节点间的时间差很敏感,如果两台机器时间差超过默认的 30 秒,任务会失败。测试环境里很多人不注意这个,结果任务跑着跑着就报“Clock skew”错误。建议所有节点都配好 NTP 同步,或者至少手动date -s对齐一次。
第三个经验是关于磁盘的。DataNode 的数据目录如果写满了,DataNode 会进入只读模式,但 NameNode 不会立即感知,导致写入失败。我建议在hdfs-site.xml里配置dfs.datanode.du.reserved,预留一部分磁盘空间,避免写满。另外可以配多个数据目录,用逗号分隔,Hadoop 会轮询写入,提升吞吐。
5.3 性能调优的几个关键参数
集群跑起来之后,如果觉得慢,可以从这几个参数入手:
dfs.blocksize:默认 128MB,如果处理大量小文件,可以调小到 64MB,但会增加 NameNode 的元数据压力。mapreduce.map.memory.mb和mapreduce.reduce.memory.mb:默认 1024MB,根据任务实际需求调整,设太小会导致频繁 GC,设太大会浪费资源。yarn.scheduler.maximum-allocation-mb:单个容器能申请的最大内存,默认 8192MB,如果任务需要更大内存,必须调高这个值。
调参的原则是:先观察,再调整。用 YARN 界面和 JobHistory 里的计数器看任务的资源使用情况,找出瓶颈再动手,不要凭感觉瞎调。
6. 集群维护的日常操作
6.1 安全下线一个 DataNode
生产环境里下线节点不能直接关机,否则会导致数据块丢失。正确流程是:
- 在
hdfs-site.xml里配置dfs.hosts.exclude指向一个排除文件。 - 把要下线的节点主机名写进排除文件。
- 执行
hdfs dfsadmin -refreshNodes。 - 在 HDFS 界面上观察该节点状态变成“Decommissioning”,等待数据块复制完成。
- 状态变成“Decommissioned”后,才能安全关机。
这个过程可能很慢,取决于节点上的数据量。如果数据量大,可以临时调高dfs.namenode.replication.work.multiplier.per.iteration加速复制,但会增加 NameNode 的负载。
6.2 元数据备份与恢复
NameNode 的元数据是集群的命根子,丢了就全完了。除了 SecondaryNameNode 的定期合并,我建议额外做两件事:一是定期把dfs.namenode.name.dir目录打包备份到远程存储;二是配置dfs.namenode.checkpoint.dir,让 SecondaryNameNode 把合并后的 fsimage 存到独立目录。
恢复的时候,把最新的 fsimage 和 edits 文件放到 NameNode 的元数据目录,然后启动 NameNode 即可。注意恢复前要确保所有 DataNode 的数据目录还在,否则即使元数据恢复了,数据块也找不回来。
6.3 日志清理与磁盘监控
Hadoop 的日志和临时文件会随着时间不断增长,尤其是 JobHistory 的日志,跑几个月就能占满磁盘。我一般配一个定时任务,每周清理一次超过 30 天的日志。JobHistory 的日志清理可以通过mapreduce.jobhistory.max-age-ms配置自动清理,默认是 7 天。
磁盘监控方面,除了系统自带的监控工具,Hadoop 本身也提供了hdfs dfsadmin -report命令,能看到每个 DataNode 的容量和使用率。我习惯把这个命令的输出定期采集,做成趋势图,这样能在磁盘写满之前提前扩容。
搭一套 Hadoop 2.7.6 集群,从规划到跑通任务,熟练的话半天能搞定,但第一次搭大概率要折腾一两天。我见过太多人卡在格式化、免密、内存配置这几个环节上。其实只要把架构理清楚,知道每个配置文件在管什么,出问题的时候去日志里找线索,大部分问题都能自己解决。这套集群搭好之后,你可以用它来跑 MapReduce、Hive、HBase,作为学习大数据底层原理的实验环境,比看视频教程管用得多。