Hadoop平台搭建实战:从伪分布式到高可用集群全指南

Hadoop平台搭建实战:从伪分布式到高可用集群全指南 1. 环境规划与模式选择为什么我建议你从伪分布式开始做Hadoop平台搭建很多人第一反应是直接上完全分布式集群。我见过不少新手一上来就照着生产环境的架构图三台五台机器铺开结果被网络配置、免密登录、进程起不来这些问题折腾到怀疑人生。说实话如果你是第一次接触Hadoop或者只是在学习阶段我更建议先走一遍单机版和伪分布式把HDFS读写、MapReduce提交、YARN调度这些核心机制跑通了再考虑扩展成多节点集群。先理清Hadoop的三种部署模式这决定了你后面所有配置文件的写法。单机模式Local Mode是最原始的状态解压Hadoop安装包后不改任何配置文件直接跑所有进程都跑在同一个JVM里主要用于跑本地测试和调试MapReduce程序。这个模式下HDFS根本没用上数据读的是本地文件系统好处是零配置秒启动缺点是没法体验分布式文件系统和资源调度的完整流程。伪分布式模式Pseudo-Distributed Mode是我个人最推荐的入门选择。它只有一台机器但Hadoop的NameNode、DataNode、ResourceManager、NodeManager这些守护进程分别以独立Java进程的方式运行配置文件写的也是真实分布式集群的格式。也就是说你在伪分布式下调通的配置和命令搬到真实集群上基本不用改。很多培训平台头歌上的Hadoop安装与伪分布式集群搭建题考察的也是这个模式因为它最能检验一个人是否真的理解了Hadoop的核心配置逻辑。完全分布式模式Fully-Distributed Mode才是生产环境的主力。需要至少三台机器角色分开部署配置起来涉及的主机名解析、SSH免密、时钟同步、磁盘规划每一项都能单独写一篇长文。这部分我会在后面专门开一节讲集群搭建但你要清楚它的地基正是伪分布式的那些配置。所以我的建议是学习路径上先把伪分布式做熟把每一个配置项搞懂再去搭集群。这样你踩过的坑会少一半而且遇到问题排查起来也有清晰的思路。以下所有实操步骤均基于Ubuntu 20.04 LTS系统这是目前国内外教程和社区里最常用的发行版兼容性和参考资料丰富度都是最好的。我搭环境时习惯把所有软件统一放在/opt目录下安装包放在/opt/soft解压后的程序放在/opt/module数据目录放/opt/data日志放/opt/logs。这个目录规划看起来多此一举但等到你维护生产集群、做日志清理和数据备份时才会发现清晰的目录结构能节省大量时间。2. 基础环境准备JDK版本、用户配置与安装包下载Hadoop底层的HDFS和YARN都是Java写的所以JDK是绕不开的第一道坎。这里先说一个很多人踩过的坑Hadoop 3.x 要求 JDK 8 起步官网明确支持 JDK 8 和 JDK 11。目前主流发行版比如Hadoop 3.3.x系列配JDK 8是最稳的组合JDK版本太高反而会遇到一些编译兼容问题。我见过有人直接用系统自带的OpenJDK 17去跑Hadoop 3.3.4结果NameNode启动报UnsupportedClassVersionError查了半天才发现是JDK版本问题。建议直接用Oracle JDK 8或者OpenJDK 8都行关键是版本要对。# 安装JDK 8 sudo apt update sudo apt install openjdk-8-jdk -y # 验证安装 java -version # 期望输出中包含 1.8.0_xxx # 查看安装路径后面配置JAVA_HOME要用 which java # 通常是 /usr/lib/jvm/java-8-openjdk-amd64/bin/java关于JAVA_HOME的配置注意一个细节Hadoop的脚本是通过$JAVA_HOME/bin/java找Java命令的如果你的JAVA_HOME配到了.../jre目录而实际JDK里有独立的bin目录启动时会直接报找不到Java。稳妥的做法是配置到JDK的根目录并确认目录下有bin文件夹。export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export PATH$PATH:$JAVA_HOME/bin然后就是Hadoop本身的下载。这里强烈建议用国内镜像源Apache官方下载速度波动大还容易断连。清华大学的TUNA镜像源是社区里公认比较稳定的直接去https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/找对应版本即可。# 以 Hadoop 3.3.4 为例 cd /opt/soft # 从清华镜像下载 wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.3.4/hadoop-3.3.4.tar.gz # 解压到 /opt/module sudo tar -zxvf hadoop-3.3.4.tar.gz -C /opt/module解压完成后建议单独建一个hadoop用户来运行Hadoop。不用root跑Hadoop是有原因的HDFS的数据节点在写入时会校验文件权限root用户权限太大跑MapReduce任务时容易出现权限管控方面的诡异问题。而且用独立用户管理会让集群的角色边界更清晰后面加节点、收日志也方便。sudo useradd -m hadoop sudo chown -R hadoop:hadoop /opt/module/hadoop-3.3.4 sudo passwd hadoop再配置一下环境变量让Hadoop命令全局可用这两个文件要区分清楚/etc/profile是系统级别的环境变量影响所有用户。~/.bashrc是当前用户级别的登录时才加载。我建议把Hadoop相关的配置写到当前用户的.bashrc里避免影响系统里其他程序。# 在 ~/.bashrc 末尾追加 export HADOOP_HOME/opt/module/hadoop-3.3.4 export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop配置完执行source ~/.bashrc然后运行hadoop version验证。如果能看到版本信息基础环境就准备好了。这一步里常见的坑是权限问题——如果你解压Hadoop时用了root到最后切换成hadoop用户会碰到无法写日志、临时文件的情况所以从一开始就把目录owner给到位。3. 伪分布式搭建五个配置文件的完整解读伪分布式的核心是把Hadoop官网自带的示例配置改造成适合自己的配置。Hadoop所有的配置项都在$HADOOP_HOME/etc/hadoop目录下你真正需要关心的是五个文件hadoop-env.sh、core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml。逐个拆解每一步都会说明为什么要这么配。3.1 hadoop-env.sh指定JAVA_HOME这个文件是Hadoop守护进程的启动环境变量。默认文件里JAVA_HOME是注释掉的你需要在文件里找到export JAVA_HOME这一行改成你本机实际路径。# 编辑 hadoop-env.sh sudo vim $HADOOP_HOME/etc/hadoop/hadoop-env.sh # 修改为你的JDK路径 export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64有些人图省事在.bashrc里已经配了JAVA_HOME觉得这里就不用管了。实际上Hadoop启动脚本在读取hadoop-env.sh时是独立开启一个子shell的不一定能拿到.bashrc里的变量。所以这个文件里的JAVA_HOME必须显式写清楚这是新手最容易忽略却最关键的一步。3.2 core-site.xml确定文件系统访问入口这个文件里最重要的配置是fs.defaultFS它决定了Hadoop的NameNode地址和端口。伪分布式模式下这个地址必须填本机主机名或IP端口官方默认是8020也有教程用9000其实两者都可以关键是保持一致。configuration property namefs.defaultFS/name valuehdfs://localhost:8020/value /property property namehadoop.tmp.dir/name value/opt/data/hadoop/tmp/value /property /configurationhadoop.tmp.dir这个配置特别容易被忽视。默认情况下Hadoop会把NameNode的元数据edits log和fsimage存储在系统的/tmp目录下而系统有一天清理/tmp时你的元数据就没了重启NameNode直接报错最典型的错误是NameNode is not formatted。所以一定要把临时目录改到持久化磁盘上。这个目录记得提前创建并赋予hadoop用户写权限。mkdir -p /opt/data/hadoop/tmp chown -R hadoop:hadoop /opt/data/hadoop/tmp3.3 hdfs-site.xml配置副本数和NameNode元数据目录configuration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name valuefile:///opt/data/hadoop/namenode/value /property property namedfs.datanode.data.dir/name valuefile:///opt/data/hadoop/datanode/value /property /configurationdfs.replication是关键。伪分布式只有一台机器如果配默认值3DataNode会尝试把每个数据块复制3份到不同节点但本机只有一个DataNode复制任务永远不满足最终表现为HDFS的块上报异常或者写入一直卡在Under replicated状态。学习阶段写成1就够了。dfs.namenode.name.dir和dfs.datanode.data.dir分别是NameNode元数据和DataNode数据块的存储路径。其中NameNode的元数据目录格式化时会把当前存在的目录写进元数据文件里如果目录不存在格式化操作可能报错或生成空目录所以建议先把目录建好。mkdir -p /opt/data/hadoop/namenode mkdir -p /opt/data/hadoop/datanode chown -R hadoop:hadoop /opt/data/hadoop3.4 mapred-site.xml 和 yarn-site.xml打通计算框架Hadoop 2.x以后MapReduce计算框架跑在YARN之上。mapred-site.xml这个文件原本不存在需要从模板复制一份然后在里面指定MapReduce的运行框架。cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xmlconfiguration property namemapreduce.framework.name/name valueyarn/value /property /configurationyarn-site.xml则是YARN的资源调度配置。伪分布式模式下需要告诉YARNResourceManager跑在哪台机器上NodeManager的附属服务有哪些。重点是yarn.nodemanager.aux-services这个参数如果不配置为mapreduce_shuffleMapReduce任务提交后去NodeManager拉取数据时会直接报错错误信息通常是Shuffle connection failed。configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.resourcemanager.hostname/name valuelocalhost/value /property /configuration3.5 格式化与启动顺序错了等于白配到这里五个配置文件就齐了。接下来是格式化NameNode这是新手翻车率最高的环节核心注意事项是只有在首次启动前才需要格式化之后每次启动直接start-dfs.sh就行。如果你重复格式化可能造成clusterID不一致DataNode起来后发现NameNode的clusterID对不上会一直拒绝服务。# 切换到hadoop用户 su - hadoop # 初始化NameNode元数据 hdfs namenode -format格式化成功后日志末尾会显示successfully formatted字样同时告诉你storage directory的路径。但这里有个坑如果你在格式化之前没有把hadoop.tmp.dir改掉或者改路径之后没有给hadoop用户目录权限格式化过程虽然可能成功但后续启动时由于目录不可写NameNode会直接死掉。排错思路是看日志日志永远是最诚实的。# 启动HDFS start-dfs.sh # 启动YARN start-yarn.sh # 验证所有Java进程是否都在 jps正常情况下你jps应该看到五个进程NameNode、DataNode、ResourceManager、NodeManager、SecondaryNameNode。少哪一个对应那个服务的日志就在$HADOOP_HOME/logs目录下。比如NameNode挂了看hadoop-hadoop-namenode-localhost.logDataNode起不来就看hadoop-hadoop-datanode-localhost.log。进程全起来了再用浏览器访问http://localhost:9870能看到NameNode的Web UI说明HDFS没问题访问http://localhost:8088能看到YARN的资源管理界面说明调度器正常。这一步验证很关键有些进程虽然活着但端口没监听这种伪健康状态特别坑人。4. 完全分布式集群搭建从单机到多机的跨越伪分布式跑通后搭真实集群就有思路了。集群规划的原则很简单元数据节点和计算调度节点分开部署数据节点和计算节点可以重合。以三节点为例我这里给出一个最经典的角色规划。节点角色masterNameNode、ResourceManager、SecondaryNameNodeslave1DataNode、NodeManagerslave2DataNode、NodeManager这个规划的逻辑是NameNode是HDFS的大脑ResourceManager是YARN的大脑两者都放在master上方便统一管理监控DataNode是数据存储和计算执行者各一台物理机互为备份。如果你有4到5台机器可以把ResourceManager单独拆到一台机器上避免主节点压力过大。4.1 主机名与网络配置首先所有节点的主机名要改好并写入/etc/hosts。这一步的坑在于Hadoop集群默认通过主机名互相访问如果你不配hosts靠DNS解析在各机房不一定通而且DNS出问题时整个集群会互相找不到节点表现是启动进程时卡很久然后超时。# 三台机器分别执行设置主机名 sudo hostnamectl set-hostname master # master节点执行 sudo hostnamectl set-hostname slave1 # slave1执行 sudo hostnamectl set-hostname slave2 # slave2执行 # 三台机器都编辑 /etc/hosts追加以下内容IP换成你实际环境 192.168.x.x master 192.168.x.x slave1 192.168.x.x slave2改完hosts后用ping master互测一下确保每台机器都能通过主机名解析到对方。4.2 SSH免密登录配置Hadoop的启动脚本本质上是远程登录到各节点去执行命令的所以master要能免密登录到所有slave节点。配置方法# 在master节点上生成密钥一路回车即可 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa # 将公钥复制到本机和slave节点 ssh-copy-id master ssh-copy-id slave1 ssh-copy-id slave2验证免密是否成功的方法很简单从master分别执行ssh slave1 jps和ssh slave2 jps如果能直接看到Java进程列表而不需要输密码说明配置成功。这一步坑很多最常见的是没有切换到hadoop用户执行上述命令导致密钥生成到了root用户目录下实际启动时用的是hadoop用户免密不生效。所以从搭建到启动所有操作建议都统一在hadoop用户下执行。4.3 配置文件修改与分发集群模式下核心配置文件比伪分布式多改几项。首先core-site.xml里的fs.defaultFS要指向masterproperty namefs.defaultFS/name valuehdfs://master:8020/value /property然后hdfs-site.xml里副本数改成三节点能承受的实际值生产环境通常写2学习环境三台机器写2即可因为NameNode一般不存数据块。同时把dfs.namenode.secondary.http-address配置到master节点的50090端口SecondaryNameNode的辅助合并职责由master承担。property namedfs.replication/name value2/value /property property namedfs.namenode.secondary.http-address/name valuemaster:50090/value /propertyyarn-site.xml里yarn.resourcemanager.hostname改成mastermapred-site.xml保持framework.name为yarn。现在重点来了配置workers文件。这是指定哪些节点作为DataNode和NodeManager的关键路径是$HADOOP_HOME/etc/hadoop/workers。把这个文件里的localhost删掉改成集群节点master slave1 slave2注意一个问题新版Hadoop里DataNode只跑在workers文件列出的节点上。如果你把master也写进workers那master既当NameNode又是DataNode生产环境不推荐这么搞所以上面这个文件我只写了slave1和slave2规划里没有让master当DataNode。配置改好后把整个Hadoop目录同步到各节点。我这里用的是最直接的方式用scp把配置分发过去cd /opt/module scp -r hadoop-3.3.4 hadoopslave1:/opt/module/ scp -r hadoop-3.3.4 hadoopslave2:/opt/module/拷贝时记得先确认slave节点的/opt/module目录存在并且目录owner是hadoop。分发完成后各节点还需要把JAVA_HOME配置到位因为刚才的hadoop-env.sh里写死了JDK路径各节点必须保证这个路径一致。我建议三台机器装同一个版本的JDK路径完全一样能省很多麻烦。4.4 初始化与集群启停集群模式下格式化操作只在master节点做一次。# 在master节点先删除之前伪分布式产生的数据如果是从伪分布式改过来的 # 注意这一步会清掉NameNode元数据和DataNode数据谨慎执行 rm -rf /opt/data/hadoop/tmp/* # 格式化NameNode hdfs namenode -format格式化后在master节点执行start-dfs.sh。脚本会读取workers文件自动通过SSH到各节点拉起DataNode和NameNode进程。再执行start-yarn.sh拉起ResourceManager和NodeManager。# master节点上 start-dfs.sh start-yarn.sh # 验证 jps # 在slave节点验证 ssh slave1 jps ssh slave2 jpsstart-dfs.sh有一个很多人不知道的细节它实际是依次调用了start-dfs.sh内部脚本去连接workers列表如果其中某个节点SSH不通整个启动过程不会报错而是直接跳过那个节点继续执行后面的。所以不要看到命令执行完就以为集群起好了一定要去每台机器上jps确认。我的习惯是起完集群后把所有节点的jps结果汇总到一张表里对比检查。这里补充一个集群模式特有的问题如果你的DataNode进程起来了但日志里有The clusterID is inconsistent之类的报错说明你之前格式化过导致不同节点的clusterID不一致。排查手段是去NameNode的current/VERSION文件和DataNode的current/VERSION文件里对比clusterID。解决方法是把各节点的数据目录清掉重新格式化这是最干净的方案但意味着你之前存的数据都没了所以格式化前务必确认数据可丢弃。4.5 集群日常启停命令详解集群搭建完成后的日常维护主要靠start-dfs.sh、stop-dfs.sh、start-yarn.sh、stop-yarn.sh这四组命令但实际使用中往往有更细粒度的启停需求。我把常用命令罗列如下方便你对照查阅命令作用hdfs --daemon start namenode单独启动某节点的NameNodehdfs --daemon stop namenode单独停止NameNodehdfs --daemon start datanode单独启动DataNodeyarn --daemon start resourcemanager单独启动ResourceManageryarn --daemon start nodemanager单独启动NodeManagerstart-dfs.sh启动整个HDFS集群start-yarn.sh启动整个YARN集群stop-all.sh同时停止HDFS和YARN这里有个个人经验如果你改了配置文件想重启某个组件千万不要图省事整集群重启除非你很清楚自己在做什么。比如你只改了yarn-site.xml中ResourceManager的内容那就只需要在master上执行stop resourcemanager start resourcemanager很快且不影响正在跑的HDFS任务。整集群重启的成本高还容易引发数据安全风险。第二个经验是stop-dfs.sh执行时如果某个节点暂时掉线或者网络不通stop脚本可能会卡住等待超时。这时候不要反复CtrlC后重新执行容易造成进程状态错乱。正确做法是手动在出问题的节点上执行对应组件的--daemon stop然后回到主节点正常停止其余部分。5. Hadoop与Zookeeper整合为高可用做准备单NameNode集群有一个致命弱点NameNode是单点一旦它所在机器宕机整个HDFS就不可用了需要人工介入恢复这个过程通常要数小时在线上是不可接受的。解决思路就是引入Zookeeper做主备切换让NameNode有Active和Standby两个角色正常情况下Active对外服务Standby通过JournalNode同步元数据一旦Active故障Zookeeper自动把Standby提升为Active。5.1 Zookeeper集群部署要点Zookeeper本身也是一个分布式协调服务生产环境至少部署3个节点因为ZAB协议需要过半数的节点达成一致3节点最多容忍1台宕机。我通常把Zookeeper部署在集群的所有机器上包括master、slave1、slave2每台机器都装一个Zookeeper实例三节点互相构成集群。# 下载Zookeeper同样走清华镜像 cd /opt/soft wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.8.1/apache-zookeeper-3.8.1-bin.tar.gz tar -zxvf apache-zookeeper-3.8.1-bin.tar.gz -C /opt/moduleZookeeper的配置核心在conf/zoo.cfg。先复制模板再修改cd /opt/module/apache-zookeeper-3.8.1/conf cp zoo_sample.cfg zoo.cfgzoo.cfg里最核心的是以下三段配置tickTime2000 dataDir/opt/data/zookeeper clientPort2181 server.1master:2888:3888 server.2slave1:2888:3888 server.3slave2:2888:3888dataDir不要放在/tmp理由和Hadoop的tmp目录一样元数据放在临时目录里重启一次就丢。clientPort是Zookeeper对外提供服务的端口Hadoop的HDFS HA组件连接Zookeeper时用的就是这个端口。server.1/2/3后面第一个端口是Zookeeper节点之间通信用第二个端口用于Leader选举。同一套集群内这些端口不能冲突。每个节点上还需要创建myid文件这个文件的内容就是当前节点在集群中的编号必须与zoo.cfg里的server.N数字一致。# master节点 echo 1 /opt/data/zookeeper/myid # slave1节点 echo 2 /opt/data/zookeeper/myid # slave2节点 echo 3 /opt/data/zookeeper/myidZookeeper的启停命令很简单# 每个节点执行 zkServer.sh start # 查看状态 zkServer.sh status启动后zkServer.sh status会告诉你当前节点是Leader还是Follower三节点里恰好会有一个Leader、两个Follower这是正常的。如果你看到某个节点报Exception: Address already in use说明端口被占用优先排查是不是之前已经启动过实例了或者有别的服务占用了2181端口。5.2 HDFS HA与YARN HA整合配置有了稳定的Zookeeper集群下一步就是把Hadoop改成HA模式。HA模式下NameNode需要两个角色namenode1和namenode2它们分别运行在不同机器上角色由Zookeeper协调。YARN的HA与之类似两个ResourceManager互为热备。配置HDFS HA的关键是hdfs-site.xml里要声明NameNode的逻辑名称以及两个NameNode对应的机器和端口property namedfs.nameservices/name valuemycluster/value /property property namedfs.ha.namenodes.mycluster/name valuenn1,nn2/value /property property namedfs.namenode.rpc-address.mycluster.nn1/name valuemaster:8020/value /property property namedfs.namenode.rpc-address.mycluster.nn2/name valueslave1:8020/value /property property namedfs.namenode.http-address.mycluster.nn1/name valuemaster:9870/value /property property namedfs.namenode.http-address.mycluster.nn2/name valueslave1:9870/value /property再配置JournalNode的地址列表JournalNode是HA模式下同步元数据的关键组件通常部署在奇数个节点上这里我们部署在master、slave1、slave2三台机器上property namedfs.namenode.shared.edits.dir/name valueqjournal://master:8485;slave1:8485;slave2:8485/mycluster/value /property然后配置自动故障转移property namedfs.ha.automatic-failover.enabled/name valuetrue/value /property property namedfs.client.failover.proxy.provider.mycluster/name valueorg.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider/value /propertyYARN HA需要在yarn-site.xml里类似地配置ResourceManager的自动故障转移指定两个RM地址并开启RM的恢复功能。这里我只提一个关键参数剩下的大致逻辑和HDFS HA一致property nameyarn.resourcemanager.ha.enabled/name valuetrue/value /property property nameyarn.resourcemanager.ha.rm-ids/name valuerm1,rm2/value /property property nameyarn.resourcemanager.ha.id/name valuerm1/value /property注意yarn.resourcemanager.ha.id这个参数每个节点上要配置成自己对应的角色被Zookeeper选为主的那个RM才会接管集群。如果你所有节点都配了同一个id两个RM会争抢成为Active日志里会出现端口绑定冲突之类的错误。政府整合这一步相当于给集群加装了高可用保险丝初次配置涉及到的参数较多我建议你在伪分布式或三节点测试环境里先完整走一遍理解每个配置项的含义再想办法应用到生产环境。我个人第一次做HA花了整整一天踩得最深的一个坑是JournalNode忘了启动结果NameNode状态一直是standby客户端根本无法读写现象和集群宕机完全一样。5.3 整合时常见的版本兼容问题有人会在整合过程中遇到NoClassDefFoundError: org/apache/hadoop/crypto这类报错。这个报错在Hadoop社区里很常见特别是在Hive配合Tez引擎运行时更容易触发本质是运行环境的classpath里缺少了Hadoop的crypto模块对应的jar包。排查思路分三步先确认Hadoop版本里是否包含crypto相关jar路径一般是$HADOOP_HOME/share/hadoop/common/lib/hadoop-shaded-guava-*.jar。然后确认HADOOP_CLASSPATH环境变量是否把$HADOOP_HOME下的lib目录都加进去了可以在命令行执行hadoop classpath来查看。最后看是不是版本冲突Hive 4.x配Hadoop 3.5或者Tez配了不兼容的guava版本都会导致类找不到。我踩过的一个实战教训是Hive 3.1.3自带的lib里有一个老版guavaHadoop 3.3.4里有新版guava两个jar在运行期随机加载导致一会儿能用一会儿报NoClassDefFoundError。解决方式是手动把Hive lib里的guava包替换成Hadoop同版本的并且保证两边版本一致然后重启HiveServer2。6. 常见报错排查与Hadoop生态联动Hadoop平台搭建过程中报错是常态不报错才需要怀疑是不是哪一步没做。这里我整理几个最高频的坑全部来自我自己的实操经历每个都值得收藏下来当排查手册用。6.1 进程起不来先看日志文件Hadoop的日志文件都写在$HADOOP_HOME/logs目录下命名规律是hadoop-用户名-角色-主机名.log。启动失败时优先看日志别到处猜原因。比如我见过太多人DataNode起不来一查日志发现是DataNode is shutdown或ClusterID mismatch。这种情况十有八九是格式化问题——你初始化了NameNode但DataNode工作目录下存有上一次的clusterID两边匹配不上。解决办法是把dfs.datanode.data.dir指向的目录清了重新格式化再启动。注意这个操作会丢失数据生产环境要极其谨慎建议先确认数据已备份。6.2 磁盘空间不足的隐性坑判断集群正常与否除了看进程还要看磁盘。DataNode的数据块会不断累积而很多人在虚拟机里搭集群时只分了20G或者30G的空间跑几个MapReduce作业就可能写满。表现是数据节点日志里出现No space left on device。这种错误不会让进程直接死亡但写入会一直失败。我的建议是在开始使用集群之前用df -h看一眼每个节点各挂载点的剩余空间给/opt目录所在的分区预留至少20G。如果你用的云主机数据盘通常挂在/data或/home下可以把dfs.datanode.data.dir配置到独立数据盘这样即使系统盘满了也不影响数据块写入。6.3 网络类问题与端口检查集群节点间通信依赖网络如果你的DataNode起来了但NameNode web界面显示的节点数少于预期先检查节点间通信。最常见的原因是防火墙没关或者端口没放行。在测试环境我一般直接关掉防火墙省得排查sudo ufw disable但生产环境不能这么粗暴需要单独放行Hadoop相关端口。Hadoop各组件默认端口如下我在排查时经常对照这张表找问题组件角色默认端口NameNode RPC8020NameNode HTTP9870DataNode RPC9866DataNode HTTP9864SecondaryNameNode HTTP9868ResourceManager HTTP8088NodeManager HTTP8042Zookeeper Client2181JournalNode RPC8485如果你在浏览器里访问NameNode的9870端口打不开但进程又是活着的大概率是防火墙把这端口挡了或者你的访问方式有问题——注意是http://而不是https://虽然这个名字起的像加密协议但默认它就是HTTP。6.4 Hive配Tez时NoClassDefFoundError的完整处理这个报错在Hadoop生态里非常典型我在多个版本组合上碰到过这里给出一个可复现的排查处理流程先确认问题的根源。NoClassDefFoundError: org/apache/hadoop/crypto的含义是JVM在运行时想加载Hadoop的crypto类但classpath里找不到对应jar。在Hive的执行流程里HiveServer2会把Hadoop的jar包加载进自己的classpath如果你用的是Tez引擎Tez还会额外加载Tez的lib目录一不小心就漏了Hadoop的某个模块。处理方法是先用系统命令确认Hadoop crypto类的jar位置find $HADOOP_HOME -name *.jar | xargs grep -l org/apache/hadoop/crypto搜出来的通常是hadoop-client-api-*.jar或者hadoop-common-*.jar。确认存在后把HADOOP_CLASSPATH显式导出并让Hive启动时读取export HADOOP_CLASSPATH$HADOOP_HOME/share/hadoop/common/*:$HADOOP_HOME/share/hadoop/common/lib/*:$HADOOP_HOME/share/hadoop/hdfs/*:$HADOOP_HOME/share/hadoop/hdfs/lib/*:$HADOOP_HOME/share/hadoop/yarn/*:$HADOOP_HOME/share/hadoop/yarn/lib/*:$HADOOP_HOME/share/hadoop/mapreduce/*:$HADOOP_HOME/share/hadoop/mapreduce/lib/*把这条加到~/.bashrc里然后重启Hadoop和Hive相关进程。如果还是报错就需要看具体是哪个类找不到了用javap -verbose或jar tf对比jar包内容确认不是不同jar版本互相覆盖导致的。这是我解决此类问题最有效的套路先定位类在哪个jar里再看classpath有没有把那个jar包含进去最后检查有没有同类的不同版本造成了排除。6.5 HDFS文件操作和MapReduce作业实测平台搭好以后强烈建议跑几个作业来验证全链路是否正常。我最常用的一套冒烟测试是这样的# 创建HDFS目录 hdfs dfs -mkdir /test # 上传一个本地文件 hdfs dfs -put /etc/hosts /test/ # 查看文件块分布情况 hdfs fsck /test/hosts -files -blocks -locationshdfs fsck的输出信息量很大你能清楚看到每个块被复制到哪台机器上块大小是否正常。如果你配置了dfs.replication2这里应该能看到每个块有2个location如果只有一个说明副本配置有问题或者节点间网络同步有问题。然后跑一个官方的WordCount示例程序这是最经典的MapReduce实验用它可以验证整个YARN调度链路是否通畅# 进入Hadoop自带示例jar的目录 cd $HADOOP_HOME/share/hadoop/mapreduce # 运行WordCount hadoop jar hadoop-mapreduce-examples-3.3.4.jar wordcount /test/hosts /test/output如果作业提交后能看到进度条跑完说明HDFS、YARN、MapReduce三层整个链路都健康。如果卡在Running job或Submitting tokens for job阶段多半是YARN的资源调度出现了问题优先去ResourceManager页面看是否有节点处于Unhealthy状态。NodeManager会定期给ResourceManager上报心跳和资源健康状况如果磁盘满了或者CPU过载它会被标记为不健康无法接受新的任务。我遇到过这样一个情况NodeManager日志里没有报错但所有任务提交到该节点后就一直等待原因是该节点的可用内存被其他进程占用过多NodeManager启动时声明的可用资源与实际可用资源不匹配任务在等待资源分配。解决方式是调低yarn.nodemanager.resource.memory-mb的值或者给NodeManager所在节点清理出足够内存。6.6 Docker镜像与快速搭建现在也有不少人是直接用Docker镜像跑Hadoop的特别是拿社区现成的镜像做快速实验。Docker方案确实省去了本机装环境的一堆麻烦几分钟就能起一个HDFS集群。但它有两个局限一是镜像的版本往往滞后不一定有你需要的Hadoop新特性二是生产环境的Docker化要处理数据持久化、网络模型、资源隔离等问题复杂度并不比传统方式低。如果你只是想快速体验Hadoop的基本功能或者跑课程设计里的MapReduce实验Docker镜像值得尝试。我的建议是优先选择GitHub上star多、维护活跃的镜像比如bde2020/hadoop-namenode和bde2020/hadoop-datanode这类带角色区分的镜像配合docker-compose可以一次拉起一个迷你集群。但要注意给容器挂载volume不然容器一删数据就全没了这和使用系统临时目录存储元数据是同一个道理。如果本机搭建困难但还想做集群实验还可以用虚拟机宿主机方案。Windows上用VMware或者VirtualBox开三个Ubuntu虚拟机给每台分配1核2G内存跑小规模测试也够用。但虚拟机方案有个坑默认的NAT网络模式下三台虚拟机虽然能互通但IP地址可能不固定重启后变化导致hosts配置失效。我的解决办法是给每台虚拟机配置静态IP这样hosts文件写死一次就能长期使用同时也建议在宿主机的hosts文件里也配上三个节点的IP映射这样你在宿主机上访问NameNode页面时就不用手动记IP了。7. 日常维护与几个值得长期坚持的习惯平台搭建不是终点日常维护才是大头。做Hadoop运维这几年我总结出几个习惯看起来不起眼但关键时刻真的能救命。第一个习惯是给集群配置统一的时钟同步。Hadoop各节点之间的交互依赖时间戳如果节点间时间差得太多轻则日志时间线混乱重则导致一些基于时间的协调逻辑失效比如租约续期、块上报时间判断。生产环境标配是配置NTP服务让所有节点向同一台时间服务器同步。测试环境再简单也得定期用date命令检查下各节点时间是否一致差异超过30秒就要警惕了。第二个习惯是每次启动集群后除了用jps验证进程还要用HDFS Web UI确认活着的DataNode数量和副本状态是否健康。有时候进程都活着但某个节点的磁盘满了这个点在NameNode页面上会有明显的显示跑任务时也会像蜗牛一样慢。日志能反映进程状态Web UI能反映集群整体的资源状态两者结合才能准确判断集群健康状况。第三个习惯是格式化前想三秒。我处理过太多因为重复格式化导致的数据丢失事故尤其是修改了dfs.namenode.name.dir之后忘了清旧目录新旧元数据混乱。我的原则是NameNode一般情况下只需要格式化一次除非代码升级或者元数据目录变更否则不要重复执行。如果你要格式化先检查当前集群里是否有未备份的数据然后停掉所有服务删干净旧目录再执行格式化。这样虽然费时间但能保证一致性。第四个习惯是日志定期归档。Hadoop的日志会越滚越大默认的log4j配置并不会自动清理长时间运行下来/opt/logs或者$HADOOP_HOME/logs可能会占用几十GB空间。我的做法是写一个简单的crontab脚本每天凌晨把超过7天的日志打包压缩超过30天的直接清理。这在生产环境是必须的测试环境养成这个习惯也能避免日志把磁盘撑爆。第五个习惯是版本记录。每当你修改了某个配置文件并验证通过就记录下来改了哪些参数、为什么改。这个记录不用多正式一个markdown文档或者电子表格就够包括修改日期、修改人通常就是你自己、修改前后参数、触发原因。后面集群出问题回溯时这份记录的价值比任何教程都大。最后说一个和Hadoop本身关系不大但非常实用的技巧善用别名和脚本。平时频繁输入的那几条命令可以在.bashrc里做成别名alias hstartstart-dfs.sh start-yarn.sh alias hstopstop-yarn.sh stop-dfs.sh alias hjpsjps; echo ---- slave1 ----; ssh slave1 jps; echo ---- slave2 ----; ssh slave2 jps我至今记得第一次把三节点集群完整跑通的那个下午看着NameNode页面里三个DataNode的节点列表、YARN页面里正常的心跳上报心里那种踏实感很难用语言描述。搭建平台的过程本质上是在训练一种排查习惯每一条报错都有它的来龙去脉每一类故障都有对应的日志线索你要做的不是焦虑而是顺着日志一层层往下查。希望这篇文章能帮你少走一些弯路早一点看到WordCount任务跑完时那串绿色的COMPLETED字样。