2026/10/17 22:08:43

Hadoop NameNode与ResourceManager高可用集群搭建

Hadoop NameNode与ResourceManager高可用集群搭建 兄弟们如果你正在折腾Hadoop完全分布式集群或者被NameNode单点故障搞得夜不能寐这篇就是写给你的。这个教程聚焦Hadoop 3.1.4版本目标只有一个把NameNode和ResourceManager的高可用HA机制一次讲透并把每一步操作都摆在你面前。什么叫保姆级就是不看任何其他资料照着这篇教程从一个干净的Linux环境起步也能把集群搭起来、跑起来、看到自动切换效果。这套配置我前前后后搭了不下十次最早用的是2.x版本后来切到3.1.4踩过的坑比写出来的多得多。这篇教程里我不会只贴配置参数每个关键配置为什么要这么写、启动顺序为什么不能乱、哪一步漏了会导致什么诡异现象都会交代清楚。1. 整体方案设计与集群规划1.1 先想明白HA到底解决什么问题Hadoop 2.x之前NameNode是整个HDFS的“大脑”它挂了整个集群就瘫痪了。虽然SecondaryNameNode能定期合并元数据但它本质上是checkpoint工具做不到秒级故障转移。HA机制的引入就是让两个NameNode一主一备、共享元数据、自动切换。3.x版本里这套机制已经很成熟ResourceManager也走上了同样的HA道路避免YARN调度器单点挂掉导致计算任务全部停摆。按照标题里的“namenode resourcemanager高可用”我们实际要部署两套HA机制HDFS HA双NameNode JournalNode集群用于同步edit log ZKFC自动故障转移控制器YARN HA双ResourceManager ZooKeeper用于状态存储与领导者选举这两套都用ZooKeeper做协调。所以整个集群的底座是先搭好一个ZooKeeper集群其他组件才能有“主心骨”。1.2 节点角色规划用3台还是5台我的建议是首次练习用3台虚拟机完全够了而且能看清HA的完整逻辑。5台当然更接近生产但节点越多排查问题越麻烦新手容易在“哪台机器上执行什么命令”这件事上绕晕。3台机器方案如下节点角色node01NameNode(Active) ResourceManager(Active) JournalNode ZooKeeper ZKFCnode02NameNode(Standby) ResourceManager(Standby) JournalNode ZooKeeper ZKFCnode03DataNode NodeManager JournalNode ZooKeeper但注意如果只有3台且namenode和resourcemanager都分散在两台节点上那剩下node03的复制因子就只能是2。如果测试环境有数据冗余需求建议至少4台node01、node02放NameNode和RMnode03、node04放DataNode。这里我按照3台标准方式来写如果你机器不够把DataNode分配到已有节点上就行不影响配置逻辑。1.3 版本选型为什么卡在3.1.4Hadoop 3.1.4是3.x系列里比较稳的一个版本。3.2.0出来以后有段时间社区反馈了一堆兼容性问题而3.1.4既能完整支持JDK8、ZooKeeper 3.4.x/3.5.x又能享受3.x的架构优化比如HDFS支持纠删码、YARN Timeline Service改进。对绝大多数学习、企业内部测试环境来说3.1.4是“闭眼不会出错”的选择。1.4 环境准备清单操作系统CentOS 7.6及以上或RHEL系我这边统一用最小化安装JDK版本1.8不要用11部分Hadoop 3.1.4组件对JDK11有兼容警告ZooKeeper版本3.4.14或3.5.7均可本教程用3.4.14最稳内存建议每台至少2G以上能上4G更好。三台加起来6~12G搭一个HA集群绰绰有余网络三台机器互通关闭防火墙或者放通指定端口后面会细说2. 基础环境配置与集群互信2.1 hosts映射与主机名这一步马虎后面全是泪很多教程里把hosts配置一笔带过我吃过亏曾因为hosts只配了IP和主机名、没有把三台机器都写全导致NameNode在格式化时报“Unable to resolve hostname”折腾了一下午。建议直接把下面内容写进每台机器的 /etc/hosts192.168.80.101 node01 192.168.80.102 node02 192.168.80.103 node03同时确保每台机器的主机名是唯一的分别执行 hostnamectl set-hostname node01/node02/node03。改完之后一定要reboot或者重新登录终端再验证hostname是否生效。这一步不验证就往下走后面所有节点间通信都会出问题。2.2 SSH免密登录一次性解决HA集群里NameNode、ZKFC之间要频繁交互不可能每次操作都输入密码。三台机器之间建议配置双向免密而不是只配单向。我推荐直接循环执行ssh-keygen -t rsa -P -f ~/.ssh/id_rsa生成密钥然后把所有公钥汇总到 authorized_keys 中。最简单的方式是ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id node01 ssh-copy-id node02 ssh-copy-id node03三台机器都执行一遍然后互相 ssh node01/node02/node03 验证。如果哪台机器要求输入密码多半是权限问题检查 ~/.ssh 目录权限是否为700、authorized_keys文件权限是否为600。2.3 JDK安装与环境变量Hadoop本身是用Java写的所以JDK是所有组件的运行基础。这里我建议直接使用OpenJDK 1.8装好之后统一配置JAVA_HOME否则后面启动脚本会报找不到Java。以每台机器都安装为例tar -zxvf jdk-8u202-linux-x64.tar.gz -C /usr/local/ cd /usr/local/ mv jdk1.8.0_202 jdk8然后在 /etc/profile 里加上export JAVA_HOME/usr/local/jdk8 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar注意一点Hadoop的start-dfs.sh脚本在找JAVA_HOME的时候读取的未必是系统的环境变量建议到hadoop-env.sh文件里也显式再加一次JAVA_HOME防止su切换用户或脚本子进程拿不到变量。2.4 时钟同步NTP与防火墙集群节点之间的时间差异直接影响ZooKeeper的投票机制和NameNode的租约判断。ZooKeeper对时间非常敏感两个节点时间差太大会导致leader频繁切换。最简单的方案是让所有节点都跟一台时间服务器同步yum install -y ntpdate ntpdate -u pool.ntp.org然后把同步命令写到crontab里每小时同步一次。防火墙方面既然是自己搭集群最省事的方式是直接清空规则systemctl stop firewalld systemctl disable firewalld生产环境不建议这么干但如果是测试环境、学习环境防火墙会挡掉大部分“莫名其妙连不上”的问题。尤其JournalNode要监听多个端口navicat式的逐条放行太费劲。等你在生产环境有了安全要求再回来精细化放行也不迟。3. ZooKeeper集群搭建HA的地基3.1 为什么HA必须要有ZooKeeper一句话概括ZooKeeper就是HA的大脑。NameNode和ResourceManager都通过ZooKeeper来进行领导者选举、故障感知和状态存储。两个NameNode谁是Active主要不是靠“互相ping”来决定的而是靠ZK的临时节点来做领导权仲裁。ZooKeeper挂掉整个HA就失去协调能力所以它的优先级最高。3.2 下载安装与配置文件将zookeeper-3.4.14.tar.gz解压到/usr/local/zookeeper然后进入conf目录复制一份zoo_sample.cfg为zoo.cfg内容如下tickTime2000 initLimit10 syncLimit5 dataDir/var/data/zookeeper clientPort2181 server.1node01:2888:3888 server.2node02:2888:3888 server.3node03:2888:3888三个端口要理解清楚2181是客户端连接端口2888是集群内部followers连leader的端口3888用于leader选举投票。很多人配置时只写了IP和2181结果集群死活起不来就是漏了后两个端口。在每台机器的dataDir目录下创建myid文件node01写1node02写2node03写3mkdir -p /var/data/zookeeper echo 1 /var/data/zookeeper/myid然后分发到三台机器确保myid编号对应hosts里的server.X编号。3.3 启动验证三台机器各自执行/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/bin/zkServer.sh statusstatus出现leader或follower就是正常的。如果三台全是follower或者全部报错优先检查myid是否配置错误、hosts映射是否生效。一个快速排查方法是执行/usr/local/zookeeper/bin/zkCli.sh -server node01:2181能连上就说明2181端口和ZK服务本身没问题。ZooKeeper启动顺序没有严格讲究但建议等一台确定成为leader后再启动其他节点以免脑裂。我第一次搭的时候三台同时启动结果某台节点反复重试连接日志刷屏。其实很正常等几十秒让它选举完就好。4. HDFS高可用配置详解4.1 核心设计两个NameNode怎么共享元数据HDFS的NameNode把元数据分为两部分fsimage文件系统镜像和edits log编辑日志。HA的核心就是把edits log实时同步到多个JournalNode上两台NameNode都去读写同一份edits log。Active NameNode写入Standby NameNode读取并持续合并到内存这样就能保证两个节点的元数据几乎实时一致。JournalNode在这里的地位等同于“日志中心”。它的角色有点像数据库的主从复制里的binlog服务器所有写操作先落JournalNode再同步到Standby节点。所以JournalNode至少要有奇数个通常是3个这样即使挂了一个剩下的也能正常仲裁数据一致性。4.2 core-site.xml核心配置进入hadoop-3.1.4/etc/hadoop目录编辑core-site.xml。configuration property namefs.defaultFS/name valuehdfs://mycluster/value /property property namehadoop.tmp.dir/name value/data/hadoop/tmp/value /property property nameha.zookeeper.quorum/name valuenode01:2181,node02:2181,node03:2181/value /property /configurationfs.defaultFS这一项是整个HDFS访问入口。配置成逻辑名称mycluster客户端访问时不直接写具体节点而是交给HA框架自动找到Active NameNode。hadoop.tmp.dir指定临时文件的根目录NameNode的元数据、DataNode的数据块存放路径都基于这里。ha.zookeeper.quorum告诉HDFS“去哪个ZK集群协调领导权”。4.3 hdfs-site.xml最完整的配置逐行解释这是整个搭建过程中的重中之重。先看完整配置再看我逐个参数讲为什么configuration !-- 集群逻辑名称 -- property namedfs.nameservices/name valuemycluster/value /property !-- 定义有多少个NameNode -- property namedfs.ha.namenodes.mycluster/name valuenn1,nn2/value /property !-- nn1的RPC通信地址 -- property namedfs.namenode.rpc-address.mycluster.nn1/name valuenode01:8020/value /property !-- nn1的HTTP页面访问地址 -- property namedfs.namenode.http-address.mycluster.nn1/name valuenode01:9870/value /property !-- nn2的RPC通信地址 -- property namedfs.namenode.rpc-address.mycluster.nn2/name valuenode02:8020/value /property !-- nn2的HTTP页面访问地址 -- property namedfs.namenode.http-address.mycluster.nn2/name valuenode02:9870/value /property !-- JournalNode地址两个NameNode都从这里同步edits log -- property namedfs.namenode.shared.edits.dir/name valueqjournal://node01:8485;node02:8485;node03:8485/mycluster/value /property !-- 客户端failover自动切换实现类 -- property namedfs.client.failover.proxy.provider.mycluster/name valueorg.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider/value /property !-- 开启自动故障转移 -- property namedfs.ha.automatic-failover.enabled/name valuetrue/value /property !-- JournalNode存放edit log的本地目录 -- property namedfs.journalnode.edits.dir/name value/data/hadoop/journal/value /property !-- fencing隔离方式 -- property namedfs.ha.fencing.methods/name valuesshfence/value /property !-- sshfence需要免密登录 -- property namedfs.ha.fencing.ssh.private-key-files/name value/root/.ssh/id_rsa/value /property !-- 默认副本数 -- property namedfs.replication/name value2/value /property !-- NameNode元数据本地存储目录 -- property namedfs.namenode.name.dir/name value/data/hadoop/hdfs/name/value /property !-- DataNode数据块存储目录 -- property namedfs.datanode.data.dir/name value/data/hadoop/hdfs/data/value /property !-- 关闭权限检查学习环境更方便 -- property namedfs.permissions.enabled/name valuefalse/value /property /configuration几个关键参数背后有门道dfs.nameservices和dfs.ha.namenodes.mycluster这两组名字必须完全一致我用myclustern1/nn2是习惯你也可以换别的但所有配置里的字符串要统一。如果你这里写的是ha-cluster下面三个地方也得跟着改少改一处就会连不上。dfs.namenode.http-address3.x版本NameNode的web端口从50070改成了9870如果你参考的是2.x教程注意别抄错。端口不匹配的话页面看着是起来了但访问不到。dfs.namenode.shared.edits.dir这里用了qjournal协议三个JournalNode地址用分号分隔不能写错一个。有个小坑是地址里最后跟的“/mycluster”必须和dfs.nameservices一致否则启动JournalNode时报无法创建日志目录。dfs.ha.fencing.methods这个理解起来稍微绕一点。当一台NameNode从Active变成Standby时为了怕它“不死心”需要有个暴力隔离手段确保同一时刻只有一台NameNode能写数据。sshfence就是通过SSH远程执行fuser命令杀掉对方进程中真正的NameNode从而防止双Active脑裂。dfs.replication设为2因为三台节点里如果一台是NameNode实际存数据的DataNode可能只有两台副本数为3会一直报块丢失。4.4 别忘了完成一个关键动作直接把配置分发到所有节点在node01上配置好core-site.xml和hdfs-site.xml后用scp把这两个文件、以及之后要配置的yarn-site.xml、mapred-site.xml等同步到所有节点。一个偷懒的方法是直接同步整个etc/hadoop目录cd /usr/local/hadoop-3.1.4/etc scp -r hadoop rootnode02:/usr/local/hadoop-3.1.4/etc/ scp -r hadoop rootnode03:/usr/local/hadoop-3.1.4/etc/注意一个常见错误有人只同步了core-site.xml忘了hdfs-site.xml结果node02启动NameNode时报找不到逻辑名称mycluster。这俩文件是配套的必须一起过去。5. YARN高可用配置详解5.1 ResourceManager为什么要配HANameNode解决了HDFS的元数据单点但YARN的ResourceManager如果挂了新的计算任务提交不了现有的任务也全部中断。生产环境里RM的可用性和NameNode一样重要。好在Hadoop 3.x的YARN HA设计得很完整Active RM把运行时状态如已提交的application写到ZooKeeperStandby RM接管后能从ZK恢复状态。有人会问YARN HA用的是ZooKeeper那为什么不直接用ZK里的临时节点来选举实际是用ZK做协调但RM状态存储走的是ZK中专门路径。你只需要知道一点YARN HA要求ZooKeeper集群必须正常运行否则两边RM都会变成standby集群无法运行新任务。5.2 yarn-site.xml逐项配置configuration !-- 开启RM HA -- property nameyarn.resourcemanager.ha.enabled/name valuetrue/value /property !-- 集群ID同个HA组内保持一致 -- property nameyarn.resourcemanager.cluster-id/name valueyarncluster/value /property !-- 两个RM的逻辑ID -- property nameyarn.resourcemanager.ha.rm-ids/name valuerm1,rm2/value /property !-- rm1的地址 -- property nameyarn.resourcemanager.hostname.rm1/name valuenode01/value /property !-- rm2的地址 -- property nameyarn.resourcemanager.hostname.rm2/name valuenode02/value /property !-- RM web应用访问地址 -- property nameyarn.resourcemanager.webapp.address.rm1/name valuenode01:8088/value /property property nameyarn.resourcemanager.webapp.address.rm2/name valuenode02:8088/value /property !-- ZooKeeper地址列表 -- property nameyarn.resourcemanager.zk-address/name valuenode01:2181,node02:2181,node03:2181/value /property !-- 开启RM状态恢复 -- property nameyarn.resourcemanager.recovery.enabled/name valuetrue/value /property !-- 状态存储的类这里配置为ZK -- property nameyarn.resourcemanager.store.class/name valueorg.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore/value /property !-- NodeManager附属服务shuffle服务给MapReduce用 -- property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property !-- 日志聚合方便查看作业日志 -- property nameyarn.log-aggregation-enable/name valuetrue/value /property property nameyarn.log.server.url/name valuehttp://node01:19888/jobhistory/logs/value /property /configuration几个容易错的地方重点说一下yarn.resourcemanager.hostname.rm1和rm2注意这个参数只填主机名不要带端口。有些人习惯写成node01:18080反而导致RM起不来。yarn.resourcemanager.store.class必须显式配置默认是不启用状态恢复的。如果漏了这行RM切换后所有application信息丢失表现就是任务列表为空、提交任务异常。yarn.log-aggregation-enable开启后Container的日志会集中保存到HDFS历史服务器的日志url要配合yarn.log.server.url后面日志查看才能正常跳转。5.3 mapred-site.xml历史服务器准备工作历史服务器JobHistoryServer用来记录和查询已经跑完的MapReduce作业。它不在HA体系里但一个完整的集群搭建必然要配上它否则作业结束之后想回头分析日志和指标就无从着手。configuration property namemapreduce.framework.name/name valueyarn/value /property property namemapreduce.jobhistory.address/name valuenode01:10020/value /property property namemapreduce.jobhistory.webapp.address/name valuenode01:19888/value /property property namemapreduce.jobhistory.intermediate-done-dir/name value/data/hadoop/history/mapreduce/intermediate/value /property property namemapreduce.jobhistory.done-dir/name value/data/hadoop/history/mapreduce/done/value /property /configuration这里有个细节历史服务器的两个目录不能提前手建NameNode格式化并启动HDFS后会自动创建。若手动创建在本地文件系统里历史服务器反而找不到路径。我第一次就犯了这个错手动建了本地路径然后历史服务器一直报目录不存在后来把这两个目录删掉让它自动生成就正常了。6. 启动全流程保姆级命令执行手册6.1 启动顺序为什么不能乱集群启动的顺序对整个搭建过程至关重要ZooKeeper必须最先启动然后JournalNode接着格式化NameNode最后才是HDFS和YARN。这个顺序里如果JournalNode没有启动就去初始化NameNode格式化过程无法写入共享edits log目录会报连接失败。下面是三台节点分步执行的具体命令按顺序执行第一步在三台节点分别启动ZooKeeper/usr/local/zookeeper/bin/zkServer.sh start第二步在三台节点分别启动JournalNode注意这里不能直接用start-dfs.sh里的自动启动journalnode方式要手动在每台节点单独执行/usr/local/hadoop-3.1.4/sbin/hadoop-daemon.sh start journalnode启动后验证journalnode进程是否存活jps应该能看到JournalNode进程。如果jps里没有多半是配置写错或者端口被占直接去logs目录看hadoop-root-journalnode-*.log日志。第三步在node01上格式化NameNodehdfs namenode -format看到 “successfully formatted” 就是成功。格式化会清空namenode目录下所有元数据执行一次就好除非集群废弃重建否则不要重复执行——这一点我要特别强调很多人遇到NameNode启动失败后反复格式化结果元数据错乱整个集群只能推倒重来。第四步初始化ZKFC在node01上执行hdfs zkfc -formatZK这个命令会在ZooKeeper中创建HA相关的路径和临时节点。如果没执行这一步后面即使两个NameNode启动成功ZKFC也无法参与leader选举Active/Standby状态永远起不来。第五步把node01格式化产生的元数据同步到node02在node02执行注意不能直接scp目录而是用hdfs命令同步hdfs namenode -bootstrapStandby这个命令会自动从node01拷贝fsimage和edits log。没有这一步node02启动后会认为自己的元数据不完整报错“There appears to be a gap”。第六步在node01上启动HDFS/usr/local/hadoop-3.1.4/sbin/start-dfs.sh脚本会读取 slaves或workers文件把DataNode启动到对应节点并把ZKFC自动带起来。启动完成后在node01和node02分别执行jps查看应该能看到NameNode、ZKFC进程node03上看到DataNode。第七步在node01上启动YARN/usr/local/hadoop-3.1.4/sbin/start-yarn.sh脚本会把ResourceManager和NodeManager启起来。注意这个脚本默认只在执行命令的机器上启动RM所以node02上的RM需要手动启动/usr/local/hadoop-3.1.4/sbin/yarn-daemon.sh start resourcemanager第八步启动历史服务器在node01执行/usr/local/hadoop-3.1.4/sbin/mr-jobhistory-daemon.sh start historyserver6.2 启动后必须做的状态检查启动不是跑完命令就完事了验证状态比启动本身更重要。检查分三层第一层进程层面jpsnode01NameNode、ResourceManager、ZKFC、JournalNode、QuorumPeerMainnode02NameNode、ResourceManager、ZKFC、JournalNode、QuorumPeerMainnode03DataNode、NodeManager、JournalNode、QuorumPeerMain第二层高可用状态层面hdfs haadmin -getAllServiceState正常输出应该是node01:8020 active node02:8020 standby如果两边都是standby说明ZKFC没有正常工作或者没有连上ZK如果两边都是active说明fencing机制没生效这属于脑裂风险必须马上排查。第三层ResourceManager状态yarn rmadmin -getAllServiceState正常输出node01:8030 active node02:8030 standby6.3 界面验证NameNode Web界面分别访问 http://node01:9870 和 http://node02:9870active节点的页面顶部会显示“Status: Active”standby节点显示“Status: Standby”YARN Web界面访问 http://node01:8088 和 http://node02:8088同样能区分active/standby历史服务器访问 http://node01:19888/jobhistory如果访问不了第一反应看防火墙第二看进程是否存活第三看端口监听情况netstat -anp | grep 9870。7. 高可用切换实战验证必须亲手测一测7.1 用kill命令暴力测试NameNode自动切换配置再好不实际测一次永远不知道会不会切换。测试方法很简单找到活跃NameNode的进程号直接kill掉。让它“死”得干脆一点在node01上执行kill -9 $(cat /tmp/hadoop-root-namenode.pid)然后观察两个现象node02上的NameNode是否从standby变成了activenode01上是否自动重启了新的NameNode进程如果开启了自动重启配置或者手动拉起确认切换状态hdfs haadmin -getAllServiceState正常情况下会看到node02变成了activenode01如果已重启变成standby。整个过程大概几十秒取决于ZK的会话超时时间。这里要说一个细节为什么旧的active被kill后standby能自动上位、而不需要人工干预因为ZKFC在ZooKeeper中注册了临时节点active的ZKFC一断临时节点消失standby的ZKFC通过watcher机制感知到了变化随即发起选举和状态变更。7.2 手动切换回去别在测试时把顺序搞乱验证完自动切换到node02后可以再把node01拉起来然后手动切回hdfs haadmin -transitionToActive nn1或者直接等node01的ZKFC自动通过选举把自己变成active。如果你想彻底验证自动切换可以把node01启动后观察一段时间。按照源码逻辑节点重新加入后是否重新成为active取决于ZK中的leader是否已经存在——如果node02已经是activenode01只会保持standby。7.3 ResourceManager切换测试ResourceManager的切换方式和NameNode不同。它依赖ZKRMStateStore切换时可以手动yarn rmadmin -transitionToActive rm1 yarn rmadmin -getAllServiceState在自动故障转移的场景下如果kill掉active RM进程standby RM会在几十秒内变成active。一个需要注意的指标RM恢复时会加载ZK里保存的application状态所以会有一定的恢复时间这期间集群可能暂时不接收新任务但一般不会超过1分钟。7.4 验证DataNode没有心跳中断切换完成后在HDFS页面上看看live nodes数量是否正常用命令验证hdfs dfsadmin -report如果DataNode全部在线说明整个集群在NameNode切换过程中没有感知到服务中断DataNode会通过重新连接新的Active NameNode完成心跳续传。8. 实战中踩过的坑每个都值得记下来8.1 NameNode格式化失败或者格式化后启动报错格式化失败最常见的原因是目录权限或已经存在旧元数据。如果以前搭过集群再次搭建前务必清理干净rm -rf /data/hadoop/hdfs/name rm -rf /data/hadoop/hdfs/data还有一个隐藏坑格式化时机器名能解析到localhost而配置里用的是node01导致格式化出来的元数据bind到了错误机器上。解决方法是检查 /etc/hosts 和 /etc/sysconfig/network 里的主机名配置确保一致。8.2 JournalNode端口8485被占用如果你在多台机器上反复重启JournalNode有时候会提示端口占用。原因是客户端的journalnode进程没被杀干净。杀干净再重启kill -9 $(jps | grep JournalNode | awk {print $1})还有一种情况是防火墙策略。虽然前面建议关防火墙但如果你用的是云主机云安全组策略是独立于防火墙的需要在安全组里放行8485、2181、2888、3888、8020、9870、8088等端口。8.3 ZKFC启动了但两个NameNode都是standby我遇到过最诡异的场景是两个NameNode都活着、ZK集群正常、ZKFC也启动了但查询状态全是standby。排查过程让我发现了一个容易忽略的点ZKFC启动时会连接ZooKeeper并创建锁节点/hadoop-ha/mycluster/ActiveBreadCrumb如果这个锁节点由于之前手动切换或格式化没清理而被残留了新的active无法抢到锁就一直保持standby状态。修复方式hdfs zkfc -formatZK这会清空HA相关的ZK节点然后重启ZKFC/usr/local/hadoop-3.1.4/sbin/hadoop-daemon.sh stop zkfc /usr/local/hadoop-3.1.4/sbin/hadoop-daemon.sh start zkfc8.4 ResourceManager切换后YARN web页面显示不正常有时RM切换了8088界面还是打不开或报错大概率是当前机器上RM进程没起来。YARN脚本没有自动启所有RM需要手动在另一台执行yarn-daemon.sh start resourcemanager。另外注意RM的web界面地址如果用了逻辑地址如rm1浏览器里访问node01:8088跳转到node02:8088的情况是正常的——因为它开启了HTTP重定向。有些浏览器对重定向敏感换个无痕窗口试试。8.5 集群时间不一致导致ZK频繁断连ZooKeeper的实现对会话超时比较敏感如果节点间时间差太多整个集群偶尔出现session expired表现就是ZKFC连接不稳定、NameNode切换频繁。解决方法就是前面提到的ntpdate定时同步把三台机器时间对齐。这个问题在测试环境里最容易忽略因为不是配置错误、不会报明确错误但会各种偶发问题排查起来极费时间。8.6 历史服务器日志看不到HDFS路径不对历史服务器跑起来后MapReduce作业日志要查看需要在yarn-site.xml中配置yarn.log.server.url指向历史服务器。如果配置缺失或者写错页面跳转不到日志。另外mapreduce.jobhistory.intermediate-done-dir和done-dir这两个目录必须存在如果之前手动建了本地路径HDFS里不存在对应目录也会失败——最好删掉它们让系统自动创建。9. 经验总结与最后的实用建议整个集群到目前为止你已经从一个没有Hadoop的环境搭起了一个具备NameNode高可用、ResourceManager高可用、历史服务器的完整平台。这台集群虽然只有三台机器但架构和生产环境基本一致——可以提交MapReduce作业、查看调度界面、观察自动切换、验证日志聚合。我个人的经验是HA集群搭建成功只是第一步后续维护才真正体现水平。日常使用中建议关注几个点一是定期查看ZooKeeper的选举状态确认三台都在线二是监控JournalNode的磁盘空间edits log日积月累可能会占用不少空间三是做任何NameNode变更操作前先备份hdfs-site.xml和core-site.xml改坏了至少能回滚。再分享一个很多教程不写的小技巧NameNode在active状态下如果直接重启机器再次启动时大概率会先进入standby状态然后等ZK选举决定是否转active这本来是正常逻辑。但如果你希望某台机器稳定作为首选的active节点可以通过调整ZKFC的选举策略或者手动执行transitionToActive来实现测试环境中手动指定反而减少不确定性。还有HA集群里HDFS的写操作性能会比单NameNode模式稍低因为每次写操作都要多写一份journal节点磁盘开销翻倍。如果你也遇到集群跑起来后写入速度明显变慢不用怀疑是自己配置错了这是HA的正常代价。生产环境通常会给JournalNode用独立的高性能磁盘来缓解。希望这套保姆级教程能帮你少走弯路。如果你按着步骤操作却卡在某个环节建议先按我整理的问题排查表对照检查80%的问题都写在里面了。搭建过程中如果发现其他奇葩问题欢迎随时交流毕竟大数据这条路踩过的坑才是真正属于自己的经验。