做Linux下的Hadoop集群搭建,几乎是所有大数据从业者入行都要趟一遍的坑。很多人照着教程敲命令,最后不是DataNode起不来,就是NameNode格式化后web界面进不去,折腾一整天最后只能把虚拟机删了重来。我从裸机到三节点集群踩过不少雷,攒下来一套从规划到验证的完整流程,这篇文章把每一步的原理和坑都写清楚,适合刚接触大数据、准备在Linux环境下手搓Hadoop集群的人,也适合已经搭了一半卡在某个环节的老哥拿来排查问题。
1. 环境准备与集群规划
1.1 集群到底要几台机器
很多人上来就问“搭建Hadoop集群是不是一定要三台机器”,我的答案是:学习阶段最少两台,推荐三台,但完全可以用一台机器加两台虚拟机的方式搞定。
生产环境至少三台起步,一台NameNode加两台DataNode,这是为了数据副本能落到不同节点上。但学习和实验没必要这么死板,我用过“1台物理机 + 2台虚拟机”的组合,也用过“三台虚拟机全在一台宿主机上”的组合,都能跑通。唯一要注意的是内存,Hadoop各组件都是Java进程,NameNode、DataNode、ResourceManager、NodeManager全开起来,基础的1G内存根本扛不住,建议每台节点至少分配2GB内存,整个集群至少保证6GB以上可用内存,否则后边跑任务会频繁触发OOM。
选型上建议直接用VMware或者 VirtualBox 建虚拟机,操作系统装CentOS 7.9或者Ubuntu Server 20.04/22.04 LTS都行。我自己长期用CentOS系,因为公司生产环境大多是这套,排查问题的时候参考文档最多。如果是纯学习,Ubuntu反而有一些优势,包管理器装依赖方便,但这属于个人习惯问题,不用太纠结。
1.2 网络、主机名与用户规划
集群规划上有个容易忽略的点:所有节点的主机名、IP、互信关系,最好在装完系统之后第一时间定下来,不要等到装Hadoop了再改。主机名建议用含义清晰的命名,比如hadoop01、hadoop02、hadoop03,我在生产环境见过用node1、master、slave这种命名,也不是不行,但在团队协作时容易产生歧义。
我常用的规划表长这样:
| 节点 | 主机名 | 角色 | IP(示例) |
|---|---|---|---|
| 节点1 | hadoop01 | NameNode / ResourceManager | 192.168.10.11 |
| 节点2 | hadoop02 | DataNode / NodeManager | 192.168.10.12 |
| 节点3 | hadoop03 | DataNode / NodeManager | 192.168.10.13 |
规划之后要做的三件基础配置,顺序别乱:
- 修改主机名,用
hostnamectl set-hostname hadoop01命令,修改后重新登录终端生效。 - 配置
/etc/hosts,把三个节点的IP和主机名映射关系写进去,注意不要用默认的localhost解析覆盖掉真实IP,否则后边HDFS各节点相互发现时会失败。 - 在每台机器上创建专门用于运行Hadoop的系统用户,比如
useradd hadoop,生产环境强烈不建议用root直接跑Hadoop,权限太大,误操作删数据的代价太高,学习阶段倒是可以偷懒,但尽量养成好习惯。
这三步做完,最好用ping hadoop02、ping hadoop03验证一下互通,再进入下一步。
2. JDK安装与基础环境配置
2.1 为什么这一步卡住了很多人
Hadoop本身是Java写的,所以JDK是绕不开的前置依赖。但版本选择上踩坑的人特别多,我见过有人装Java 17去跑Hadoop 2.x,结果一堆API不兼容的报错,最后只能重新装。这里给一个稳妥的组合:Hadoop 2.x系列配JDK 8,Hadoop 3.x系列配JDK 8或JDK 11,不建议直接用太高版本的JDK,官方兼容列表没跟上,坑很多。
下载JDK时,Oracle JDK和OpenJDK都能用,学习环境用OpenJDK就够了,命令是yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel,Ubuntu系用apt install openjdk-8-jdk。有一点要注意:有些教程让你从Oracle官网下载.tar.gz包手动解压,这样做的好处是路径可控,坏处是Oracle下载页面的按钮经常变化,而且需要登录,反而劝退新手。用包管理器装,然后定位到安装路径,性价比更高。
安装完一定要验证版本,java -version能输出版本信息还不算完,还要确认javac在不在,因为Hadoop源码编译场景和部分工具需要JDK而不是仅JRE。用which javac检查一下,没有的话单独装devel包。
2.2 环境变量配置的那点细节
环境变量配置是所有Linux相关教程里的高频翻车点。正确的位置是/etc/profile或者用户级的~/.bashrc,我在生产环境习惯把JAVA_HOME写到/etc/profile.d/java.sh,这样更干净,卸载时删一个文件就行。核心内容如下:
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk export PATH=$PATH:$JAVA_HOME/bin这里有个关键点:直接在终端执行export只能临时生效,很多人配完当天能用,第二天重开终端就找不到java命令,就是因为没写进配置文件。写完之后要source /etc/profile刷新,或者重新登录终端。
另外,Hadoop自身的启动脚本会去读JAVA_HOME,如果系统里装了多个JDK,可能导致HDFS的各个守护进程用的是不同版本,启动时不会立刻报错,但运行一段时间会出现一些诡异问题。所以最好让/etc/hosts和JDK路径在所有节点上保持一致,我后来都是把所有节点统一装同一个小版本的JDK,从源头避免这类问题。
3. Hadoop安装与五份核心配置详解
3.1 下载安装包该注意什么
Hadoop安装包建议从Apache官网下载,但官网速度不理想,国内直接下经常断。我习惯用清华大学开源软件镜像站下载,确实快很多,版本也全。选择版本时,3.3.x是目前最稳定的系列,功能完整,社区反馈也多,遇到问题容易搜到解决方案,不建议一上来就尝鲜最新版本。
下载完解压时有个细节:Hadoop的tar包解压后目录名带版本号,比如hadoop-3.3.6,我习惯再做一个软链接,ln -s /opt/hadoop-3.3.6 /opt/hadoop,这样后续所有配置路径都写着/opt/hadoop,以后升级版本时只需改软链接,不用改一堆配置文件里的路径。这个习惯帮我省过不少事。
还有一点经常被忽略:解压后一定要确认bin目录下的脚本有执行权限,解压一般自带了,但如果是从Windows下解压再传到Linux的,权限经常是乱的,跑chmod +x /opt/hadoop/bin/* /opt/hadoop/sbin/*顺手补一下。
3.2 五份XML配置逐个拆解
Hadoop配置的核心在etc/hadoop/目录下的几个XML文件。新手最容易犯的错是照抄网上的片段,完全不理解参数含义,出了问题根本没法排查。我逐个说一下关键项。
第一份:core-site.xml,全局核心配置。这里必配的是fs.defaultFS,它决定了HDFS的NameNode地址和端口,比如hdfs://hadoop01:9000。端口9000被很多教程沿用,但这个端口其实可以自定义,只要全局一致就行。另一个参数hadoop.tmp.dir也很关键,它指定了NameNode和DataNode存放元数据和数据块的根目录,默认值在/tmp底下,这会导致重启系统后数据丢失,所以一定要改到独立目录,比如/data/hadoop/tmp。
第二份:hdfs-site.xml,HDFS专属配置。必配的是dfs.namenode.name.dir和dfs.datanode.data.dir,分别指定NameNode元数据存储路径和DataNode数据块存储路径。生产上这两个目录要分开,而且在不同的磁盘上,学习环境下至少要做到不放在/tmp下。dfs.replication默认是3,如果集群只有两个DataNode,副本数最好改成2,否则会出现数据块一直在等待副本写入、状态显示异常的情况。
第三份:mapred-site.xml,看名字就知道是MapReduce相关配置。关键是mapreduce.framework.name,必须设成yarn,不配的话任务会在本地运行而不是提交到集群,很多人跑WordCount发现日志里写着LocalJobRunner,就是这一步没配对。
第四份:yarn-site.xml,资源调度配置。必配的是yarn.nodemanager.aux-services,值要设置成mapreduce_shuffle,这是MapReduce任务执行shuffle阶段时NodeManager需要提供的辅助服务,漏配会导致任务在Reduce阶段卡住或者直接失败。另外如果ResourceManager不在NameNode这台机器上,还需要显式配yarn.resourcemanager.hostname。
第五份:实际上还有workers文件(Hadoop 3.x叫workers,2.x叫slaves),它列出了所有DataNode主机名,每行一个。我见过有人在这里也配上空格分号逗号分隔,结果后面的节点全都没被识别,正确格式就是每行一个主机名,不要有任何多余符号。
配置完这几份文件,最稳妥的验证方式是在所有节点执行/opt/hadoop/bin/hdfs version,能正常输出版本信息说明环境变量和基础配置没问题,再继续往下。
3.3 目录结构规划,提前想好能少走弯路
除了配置文件,目录结构也要提前规划。HDFS的NameNode元数据目录、DataNode数据目录、日志目录,我都建议规划成独立分区或者独立磁盘。很多真实故障都是根分区被日志或数据写满导致集群崩溃,反正我在这上面吃过亏,后来养成了规划目录时把/data分区单独挂出来的习惯。
mkdir -p /data/hadoop/tmp mkdir -p /data/hadoop/hdfs/name mkdir -p /data/hadoop/hdfs/data mkdir -p /data/hadoop/logs创建好之后,把目录属主改成运行Hadoop的用户,chown -R hadoop:hadoop /data/hadoop。这一步容易被忽略,因为如果你用root启动Hadoop,目录权限的问题不会立刻暴露,但换成普通用户启动时,各种Permission denied就来了,到时候很难定位。
4. 集群启动与验证全流程
4.1 格式化NameNode,一次就够了
环境配好之后,第一个关键动作是格式化NameNode。命令是hdfs namenode -format,执行位置必须在NameNode节点上。这个动作相当于给HDFS文件系统做初始化,会生成一个clusterID,DataNode启动时会拿着自己的ID跟NameNode比对,不一致就拒绝注册。
这里有个新手高发问题:很多人在集群第一次启动失败后,直接重新执行格式化,导致NameNode生成新的clusterID,而老的DataNode还记录着旧的clusterID,数据节点全部注册不上。解决方法是:格式化前先删除NameNode和DataNode的数据目录,确保两边都是全新的,否则就得手工改current/VERSION文件里的clusterID,把DataNode的都改成NameNode最新的。
另外,Hadoop 3.x里格式化时看到大量INFO日志,最后提示successfully formatted才算成功,如果只是看到一堆WARN和异常,说明JDK或环境变量有问题,排查完再格式化,别带着错误继续硬启动。
4.2 启动HDFS和YARN的顺序有讲究
启动顺序我认为是:先HDFS后YARN。在NameNode节点执行/opt/hadoop/sbin/start-dfs.sh,然后执行/opt/hadoop/sbin/start-yarn.sh,最后可选启动mapred --daemon start historyserver来开JobHistory服务。
启动完成后,用jps命令查看Java进程。各节点上应该看到这些进程:
| 节点 | 预期进程 |
|---|---|
| hadoop01 | NameNode、ResourceManager、DataNode、NodeManager |
| hadoop02 | DataNode、NodeManager |
| hadoop03 | DataNode、NodeManager |
很多人看到自己NameNode节点上也有DataNode进程会困惑,其实这取决于workers文件里是否包含了这台机器,如果配置了它做DataNode,那出现DataNode进程就是正常的。
jps看到进程不代表集群正常,还要看web界面。Hadoop 3.x里NameNode的Web UI端口是9870,ResourceManager的Web UI端口是8088,浏览器打开http://hadoop01:9870应该能看到节点列表和文件系统概览,打开http://hadoop01:8088能看到资源调度页面。如果页面打不开,多半是防火墙没放行端口或hosts解析不对。
4.3 跑一个WordCount,验证集群真的能用
进程都在、页面能开,还不能说明集群能干活,跑一个实际任务才算数。第一步先在HDFS上建目录并上传文件:
hdfs dfs -mkdir -p /input hdfs dfs -put /opt/hadoop/etc/hadoop/core-site.xml /input/然后跑官方自带的WordCount示例:
hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar wordcount /input /output任务跑完后,查看输出:
hdfs dfs -cat /output/part-r-00000如果能看到统计结果,说明整个链路从HDFS到YARN到MapReduce全部通了。这一步我强烈建议不要跳过,因为Web界面正常只能说明进程活着,不能说明计算调度链路没问题。我第一次搭集群就是进程全部正常,但任务提交后卡在ACCEPTED状态不动,最后发现是yarn-site.xml里少了aux-services配置。
5. 常见问题与排查实录
5.1 SSH免密登录失效的三种情况
SSH免密是分布式部署的基础,因为start-dfs.sh脚本需要通过SSH远程到每台DataNode节点启动进程。配置步骤很简单:在NameNode节点生成密钥,ssh-keygen -t rsa -P '',然后把公钥分发到所有节点(包括自己),命令是ssh-copy-id hadoop@hadoop01、ssh-copy-id hadoop@hadoop02、ssh-copy-id hadoop@hadoop03。
免密失效最常见的三种原因:一是~/.ssh/authorized_keys文件权限不正确,这个文件不能是别人可写的,否则SSH出于安全策略直接拒绝,解决办法是chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys;二是目标节点是用root安装的,但运行Hadoop的用户是hadoop,密钥放错了用户的目录,SSH按用户名去找对应家目录下的公钥,放错地方自然不生效;三是本机回环测试失败,ssh hadoop01都提示需要密码,说明公钥压根没分发成功,手动把公钥追加到目标机器的authorized_keys里就行。
5.2 NameNode格式化后DataNode注册不上
这个我前面提过,但值得单独展开。DataNode启动时会去本地数据目录读取自己的clusterID,然后跟NameNode上报,两边不一致时DataNode会一直报Incompatible clusterIDs,进程看起来是活着,实际上没注册进集群,Web界面的Live Nodes数一直不对。
解决思路就两条:要么删掉所有节点上的current目录后重新格式化,要么手动改DataNode的VERSION文件,把clusterID改成和NameNode一致。我推荐前者,因为真正的生产环境不会轻易删除元数据,但在学习阶段重来成本低,而且重新格式化后的环境更干净。删之前先确认没有重要数据,格式化命令会把元数据清空,这一点说了无数遍还是有人中招。
5.3 DataNode能启动但集群显示节点数不对
还有一种情况是DataNode连NameNode失败,日志里报Connection refused。这个问题的根源90%是hosts配置没生效。DataNode通过主机名去解析NameNode,如果你的/etc/hosts里把hadoop01解析成一个错误的IP,连接自然失败。排查思路:在DataNode节点上先ping hadoop01,确认解析结果,再用nc -vz hadoop01 9000测试端口连通性。
另外,如果DataNode和NameNode不在同一个局域网段,要特别注意防火墙和网络策略,不要只盯着Hadoop本身看。经验是先把防火墙关闭或者放行对应端口,跑通之后再按安全要求收紧规则,这样能快速缩小排查范围。
5.4 任务提交后一直卡在ACCEPTED状态
任务卡在YARN的ACCEPTED状态不动,这个问题我踩过一次就记住了。当时Web界面显示作业一直在排队,等了十分钟都没开始跑。排查方向是看NodeManager的日志,发现NodeManager在跟ResourceManager通信时一直报错,最后定位到yarn-site.xml中yarn.nodemanager.resource.memory-mb设置过大,超过了虚拟机实际可用内存。
这里给一个内存分配的参考经验:如果单节点可用内存是2GB,yarn.nodemanager.resource.memory-mb建议设置为1536,yarn.scheduler.maximum-allocation-mb设置成1536,这是给NodeManager预留系统和其他进程的空间。很多教程直接给4096之类的值,在小内存机器上完全跑不动。MapReduce任务本身也有内存参数,mapreduce.map.memory.mb和mapreduce.reduce.memory.mb默认是1024,大任务需要根据数据量调大,但前提是NodeManager的容器总和不能超过它的总内存。
5.5 磁盘满导致的隐性故障
HDFS运行一段时间后,磁盘使用率会悄悄涨上来,最典型的表现是数据块写入报错或者节点被标记为不健康。排查时用hdfs dfsadmin -report查看各节点容量和空间使用情况,再用df -h看本地磁盘。很多人只关注HDFS的存储目录,忽略了日志目录和临时目录,日志文件无限增长会先写满根分区,到时候表面上HDFS还有空间,实际上集群已经处于亚健康状态。日志管理建议开启Hadoop的日志轮转功能,或者定时用cron清理超过一定天数的日志文件,这个性价比极高的操作很多人没做。
6. 集群日常维护与优化建议
6.1 资源参数怎么调才合理
集群搭完能跑,只是第一步,真正让人头疼的是参数调优。核心的调优方向是保证资源分配符合机器实际配置。我见过有人在一台2G内存的虚拟机上,给YARN分配了4G的容器上限,结果任务一提交NodeManager直接被系统OOM killer干掉,进程消失后从web界面看就是节点宕机,其实是被系统杀了。
一个简单可用的策略:先算出每台机器可用物理内存,去掉给系统和其他服务保留的20%,剩下的分配给YARN。比如8G内存的机器,yarn.nodemanager.resource.memory-mb可以设成6144左右。CPU的yarn.nodemanager.resource.cpu-vcores一般按核数设置,但要保留一个核给系统,比如4核的机器设成3。这些参数改完一定要重启集群才生效,我经常看到有人改了配置不重启就怀疑没生效,其实只是参数没有被重新加载。
6.2 安全模式与副本数的那点事
集群启动时NameNode会进入安全模式(Safe Mode),这个阶段HDFS只接受读取不接受写入,本质是NameNode在启动时加载元数据并等待DataNode上报数据块,确认副本数量达到要求后才自动退出。新手看到Web界面上写着Safe Mode ON就以为集群坏了,实际上等一会儿就会自动变OFF。
如果等很久还在安全模式,先检查有多少节点上线,再检查副本数是否满足要求。有一种常见场景:你改了dfs.replication从3改成2,但历史文件还是3副本,DataNode数量不够就会一直进不了正常状态。这时可以用hdfs dfsadmin -safemode leave强制退出,或者等DataNode补副本,不过强制退出只是权宜之计,数据持久性风险依然存在。
6.3 备份和日志检查,平时多看一眼能省大事
最后聊点运维层面的经验。HDFS上重要的是NameNode的元数据,也就是dfs.namenode.name.dir下的fsimage和edits文件,这些文件一旦损坏,整个集群的数据就变成了无法读取的裸块。最简单的备份方案是定期把这些文件打包复制到一个独立目录或另一台机器,很多公司还会用HDFS本身的SecondaryNameNode机制做自动合并与备份。在Hadoop 3.x里已经不建议用SecondaryNameNode了,更推荐配置NameNode高可用,但这对于学习环境来说太重,定期手动备份元数据就够用。
日志检查也是有规律可循的,我习惯在遇到问题前先看三类日志:NameNode日志里有没有Exception、DataNode日志里有没有Connection refused、YARN日志里有没有Container killed。平时多对这几个关键词保持敏感,很多问题都不用等到用户报障就能提前发现。集群跑久了,节点系统盘空间不足、磁盘读写变慢这类问题,也大多能从日志里看出端倪。
我在实际搭建和运维Hadoop集群的过程中,最深的体会是:集群搭不起来,90%的问题出在配置文件的细节和节点之间的互通性上,而不是Hadoop本身有多难。你只要把hosts解析、SSH免密、JDK版本、目录权限这些基础检查一遍,再严格按照规划步骤来,一次成功率会高很多。最后再分享一个小技巧:每改完一个关键的XML配置,不要急着重启集群,先在节点上用hdfs --config或yarn --config指定配置跑一个最简单的命令验证语法,比如hdfs dfs -ls /,能正常返回结果再重启,这样能避免很多“改了配置但没生效”的无效排障时间。