Hadoop 3.1.4 HA集群搭建实战:NameNode和ResourceManager高可用配置 做大数据基础架构的人早晚都要过一关给 Hadoop 配 HA。我最早搭的是单点 NameNode数据量小的时候还勉强能撑等真正接手每天跑几十个定时任务的集群时才发现单点真的是拿运气赌服务可用性——一次断电、一次磁盘满、一次进程假死整个集群就得停摆。这篇文章记录的是一套能直接抄作业的 Hadoop 3.1.4 完全分布式 HA 搭建流程NameNode 和 ResourceManager 都做高可用附带历史服务器和日志聚合覆盖从环境准备、核心机制、配置文件、启动顺序到故障切换演练的完整链路。文章不会停留在“把配置贴出来”就完事我会把每个关键参数为什么要这么写、哪个环节最容易翻车、启动报错怎么排查都讲清楚。适合两类读者一类是刚接触大数据、想在一周内把 HA 集群跑起来的初学者另一类是已经在用单点 Hadoop、准备把生产集群改造成高可用架构的运维同学。无论你手头是三台虚拟机还是五台物理机按这个思路调整角色分配就行。1. 动手前先想清楚节点规划、版本选择和 HA 的基本盘1.1 为什么选 Hadoop 3.1.4 而不是更高版本版本选择这事我的建议很务实生产环境求稳不带第一个吃螃蟹。Hadoop 3.1.4 属于 3.x 里非常成熟的版本社区踩坑记录多、网上资料全、兼容性好配套组件也好找。3.2 和 3.3 系列虽然功能更新但某些发行版环境下的依赖冲突和处理 MapReduce 任务时的行为差异会让新人排查起来很痛苦。如果你的集群跑的是 Spark、Hive、Flink 这类上层计算框架一定要先确认它们官方支持的 Hadoop 版本范围。我见过有人装 Hadoop 3.3 之后发现某版本 Flink 连接器不兼容最后不得不降级重搭白白浪费两天时间。3.1.4 对主流计算框架的适配度很高这也是我推荐它的原因。本教程基于 OpenJDK 1.8 环境测试。Hadoop 3.x 对 Java 版本有明确要求JDK 1.8 是兼容性最好、出问题最少的选择。用更高版本的 JDK 出发时可能遇到编译级别的报错新手不建议折腾。1.2 五节点角色分配与硬件规划HA 集群的最小可用规模是 3 台机器但对于想彻底模拟生产环境的场景我更推荐 5 台。理由很简单NameNode 和 ResourceManager 做 HA 各占两个节点JournalNode 需要奇数个3 个ZooKeeper 也需要奇数个3 个如果机器太少这些角色会互相挤占出问题的时候不太好判断是谁在拖后腿。我这里给出的规划是一套五节点方案每台机器建议 4 核 8G 以上硬盘 500G 起步节点角色分配说明hadoop01NameNode(Active)、ZKFC、ResourceManager(Active)、ZooKeeper主控节点负载较重hadoop02NameNode(Standby)、ZKFC、ResourceManager(Standby)、ZooKeeper备控节点和 01 互为备份hadoop03JournalNode、DataNode、ZooKeeper三台 JournalNode 之一hadoop04JournalNode、DataNode、JobHistoryServer同时承载历史服务器hadoop05JournalNode、DataNode纯存储节点一个很容易被忽略的点JournalNode 和 ZooKeeper 都要求奇数个因为选举机制需要“多数派”才能工作。5 节点方案里放 3 个 JournalNode、3 个 ZooKeeper正好满足要求。如果你的机器只有 3 台也可以把 ZooKeeper、JournalNode、NameNode、DataNode 全部压到 3 台上能跑通但故障隔离性就差了生产环境不推荐。安装前还有三件事必须确认所有节点的主机名和 /etc/hosts 映射已经配置好后面所有配置都基于主机名不写死 IP所有节点的系统时间已经同步。这一点经常被无视但 JournalNode 和 NameNode 之间的通信对时间漂移非常敏感偏差超过秒级就可能出现无法同步 edit log 的诡异报错防火墙关闭或者至少把 Hadoop 相关端口放通。在实验环境里我建议直接 systemctl stop firewalld systemctl disable firewalld避免排查问题时被“端口不通”干扰。2. HA 高可用到底在解决什么问题故障切换的核心机制2.1 单节点“死”在生产链路里的真实场景没有 HA 的 Hadoop 集群里NameNode 是唯一的核心它维护着整个文件系统的元数据Namespace、Block 位置信息等。一旦 NameNode 所在机器宕机整个集群立即失联所有计算任务中断数据无法读写。你可能想说“恢复机器重启不就行了”但问题是如果宕机是因为硬盘损坏而不是系统崩溃元数据就难说能保住多少了。更何况重启期间跑批任务完全停摆业务方会拿着工单追你到怀疑人生。HA 的核心目的就是让备用节点在几十秒内自动接管把停机时间压缩到业务无感。2.2 NameNode 高可用的四个关键组件NameNode 的高可用不是单靠“两台机器跑同一个进程”就行的它涉及四个协作组件ZooKeeper承担“选主大脑”的角色。两个 NameNode 启动后都会去 ZooKeeper 注册并争取 Active 身份ZooKeeper 通过分布式锁保证同一时刻只有一个 NameNode 成为 Active共享存储JournalNodeActive NameNode 会把写操作产生的 edit log 实时写入 JournalNode 集群Standby NameNode 持续从 JournalNode 读取这些日志并应用到自己的内存中保证两个 NameNode 的元数据时刻对齐ZKFCDFSZKFailoverController每个 NameNode 节点上都有一个独立的 ZKFC 进程它负责监控本机 NameNode 状态往 ZooKeeper 里写健康信息并在检测到异常时主动触发切换Fencing隔离机制这是很多人会忽略但至关重要的一环。切换时要确保旧的 Active NameNode 真正退出工作防止两个节点同时写元数据导致数据错乱也就是所谓的“脑裂”。常见配置是 sshfence通过 SSH 登录旧节点执行 kill 命令或者配置 shell 命令做隔离。2.3 ResourceManager 的 HA 思路有什么不同ResourceManager 的高可用逻辑和 NameNode 类似也是两个 RM 注册到 ZooKeeperActive 节点负责接收客户端请求和分配资源。区别在于 RM 的状态存储方式它不需要 JournalNode 这样的共享日志集群而是依赖 ZooKeeper 本地状态目录。配置时需要设置yarn.resourcemanager.recovery.enabledtrue这样 Active RM 会把应用状态、调度器状态保存下来切换后新的 Active RM 可以从 ZooKeeper 和本地文件系统恢复。所以 RM 的高可用对 ZooKeeper 的依赖更直接ZooKeeper 挂了RM 的选主也会瘫痪。2.4 理解这几行配置背后的逻辑如果你已经看过了不少 HA 教程会发现配置里总有几个固定的名字hacluster、nn1、nn2、mycluster、rm1、rm2。这些不是随便写的fs.defaultFShdfs://hacluster告诉客户端这个集群的名称服务叫hacluster它会去查找hacluster对应的 NameNode 地址列表dfs.client.failover.provider指定的ConfiguredFailoverProxyProvider负责让客户端自动探测哪个 NameNode 是 Active并自动实现“先连 nn1不行再连 nn2”的重试逻辑yarn.resourcemanager.cluster-id标识的是 YARN 集群 ID客户端拿到这个 ID 才能从 ZooKeeper 中找到正确的 RM 主从信息。理解这些名字的含义比背配置更重要因为以后你要是加第三个 NameNode 或迁移集群只需要改这些名字对应的清单而不是大段重写配置文件。3. 基础环境搭建JDK、主机映射、免密登录、时钟同步与 ZooKeeper 集群3.1 JDK 安装与 hosts 映射在所有节点上安装 OpenJDK 1.8可以走最简单的方式yum install -y java-1.8.0-openjdk安装后验证一下版本java -version # 至少是 1.8.0 某一版本不是更高版本就行然后配置每台机器的 /etc/hosts。我这里用内网模拟网段 192.168.109.x192.168.109.101 hadoop01 192.168.109.102 hadoop02 192.168.109.103 hadoop03 192.168.109.104 hadoop04 192.168.109.105 hadoop05这里用 IP 还是主机名有讲究集群内部通信尽量用主机名因为后续机器的内网 IP 可能变化而主机名配置一次就不会变。我之前出过一次事故某台机器 DHCP 分配到新 IP所有依赖旧 IP 的 DataNode 全部成为“孤儿节点”改 hosts 之后重启整个集群才恢复。3.2 SSH 免密登录一定要做到“双向免密”Hadoop 启动脚本会通过 SSH 从主控节点登录到其他节点启动进程所以ssh 必须免密。这里最容易犯的错是只做了主节点到其他节点的免密结果从 standby 节点执行 start-dfs.sh 时又卡住。最简单的做法是让每台机器都生成密钥然后把所有机器的公钥互相同步# 在所有节点执行 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa # 然后把每台机器的公钥汇总到 authorized_keys或者用 ssh-copy-id 互相拷贝 ssh-copy-id hadoop01 ssh-copy-id hadoop02 # 其他节点同理保证任意两台机器之间都能免密测试的时候不要只测一条链路我习惯在每台机器上循环执行for host in hadoop01 hadoop02 hadoop03 hadoop04 hadoop05; do ssh $host hostname; done如果哪一台输出了 hostname说明免密没问题。另外要确认每台机器对自身也能免密因为有些 Hadoop 脚本会 SSH 到本机。3.3 ZooKeeper 集群安装与 zoo.cfg 配置HA 依赖 ZooKeeper所以在配置 Hadoop 之前先把 ZooKeeper 集群搭好。我在实际部署中用的是稳定版 ZooKeeper 3.4.143.1.4 对应的 Hadoop 自带的 ZKFC 对它支持很完善。解压后每台节点的conf/zoo.cfg基本一致tickTime2000 initLimit10 syncLimit5 dataDir/opt/zookeeper/data clientPort2181 server.1hadoop01:2888:3888 server.2hadoop02:2888:3888 server.3hadoop03:2888:3888然后在各节点的 dataDir 里创建myid文件# hadoop01 echo 1 /opt/zookeeper/data/myid # hadoop02 echo 2 /opt/zookeeper/data/myid # hadoop03 echo 3 /opt/zookeeper/data/myid这里有一个我踩过三次的坑dataDir如果没有手动创建ZooKeeper 会启动失败。另外myid必须和 zoo.cfg 里的 server 编号一一对应写错了会出现该节点一直处于 unknow state 的怪现象。启动 ZooKeeper 并确认状态# 三台节点分别启动 /opt/zookeeper/bin/zkServer.sh start # 在任意一台执行 /opt/zookeeper/bin/zkServer.sh status # 应该看到 leader/follower 输出且 mode 不是 standalone判断 ZooKeeper 集群是否成功不要只看进程有没有起来要看 zkServer.sh status 的输出。如果显示 standalone 或连接被拒绝说明集群选举和通信有问题后面 Hadoop 的 HA 一定起不来。4. 关键配置逐项拆解五大 XML 文件抄作业版4.1 配置文件总览与路径约定Hadoop 3.1.4 的核心配置在$HADOOP_HOME/etc/hadoop/目录下。你需要关注 5 个文件core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml、workers3.x 里 workers 替代了旧版本的 slaves。下面我把每个文件的关键项拆开解释方便你理解而不是死记。4.2 core-site.xml全局入口配置configuration !-- 指定使用的文件系统地址hacluster 是自定义的 nameservice -- property namefs.defaultFS/name valuehdfs://hacluster/value /property !-- 临时目录最好单独分配避免 /tmp 被系统清理 -- property namehadoop.tmp.dir/name value/data/hadoop/tmp/value /property !-- 指定 ZooKeeper 集群地址 -- property nameha.zookeeper.quorum/name valuehadoop01:2181,hadoop02:2181,hadoop03:2181/value /property !-- 连接 NameNode 的超时时间调大点避免 HA 切换时客户端报连接超时 -- property nameipc.client.connect-timeout/name value10000/value /property /configurationhadoop.tmp.dir这个路径很关键NameNode 格式化产生的元数据就放在这里。如果你把默认的/tmp/hadoop-${user.name}留着系统重启时清空 /tmp集群直接瘫痪。生产环境务必指定到独立数据盘。4.3 hdfs-site.xmlNameNode HA 的核心战场configuration !-- 名称服务标识 -- property namedfs.nameservices/name valuehacluster/value /property !-- 这个 nameservice 下有两个 NameNode 逻辑名 -- property namedfs.ha.namenodes.hacluster/name valuenn1,nn2/value /property !-- nn1 的 RPC 和 HTTP 通信地址 -- property namedfs.namenode.rpc-address.hacluster.nn1/name valuehadoop01:8020/value /property property namedfs.namenode.http-address.hacluster.nn1/name valuehadoop01:9870/value /property !-- nn2 的 RPC 和 HTTP 通信地址 -- property namedfs.namenode.rpc-address.hacluster.nn2/name valuehadoop02:8020/value /property property namedfs.namenode.http-address.hacluster.nn2/name valuehadoop02:9870/value /property !-- JournalNode 共享 edits 目录 -- property namedfs.namenode.shared.edits.dir/name valueqjournal://hadoop03:8485;hadoop04:8485;hadoop05:8485/hacluster/value /property !-- 客户端自动故障转移代理 -- property namedfs.client.failover.proxy.provider.hacluster/name valueorg.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider/value /property !-- 隔离方法先 ssh 到旧节点强制杀掉进程 -- property namedfs.ha.fencing.methods/name valuesshfence/value /property property namefs.ssh.connect-timeout/name value30000/value /property !-- 每个 JournalNode 存储 edit log 的目录 -- property namedfs.journalnode.edits.dir/name value/data/hadoop/journal/value /property !-- 允许 HDFS 自动故障转移 -- property namedfs.ha.automatic-failover.enabled/name valuetrue/value /property /configuration关于sshfence多说一句它要求执行 failover 的节点能免密 SSH 到目标 NameNode并且有权限 kill 进程。如果无法配置 root 免密可以换成shell(/bin/true)这种宽松的隔离方式但这就等于放弃了强隔离生产环境不推荐。4.4 yarn-site.xmlResourceManager 高可用配置configuration !-- 启用 RM HA -- property nameyarn.resourcemanager.ha.enabled/name valuetrue/value /property property nameyarn.resourcemanager.cluster-id/name valuemycluster/value /property property nameyarn.resourcemanager.ha.rm-ids/name valuerm1,rm2/value /property !-- rm1 配置 -- property nameyarn.resourcemanager.hostname.rm1/name valuehadoop01/value /property property nameyarn.resourcemanager.hostname.rm2/name valuehadoop02/value /property !-- 客户端访问 RM 的地址HA 前走实际机器HA 后走逻辑地址 -- property nameyarn.resourcemanager.address.rm1/name valuehadoop01:8032/value /property property nameyarn.resourcemanager.address.rm2/name valuehadoop02:8032/value /property !-- Web UI 端口 -- property nameyarn.resourcemanager.webapp.address.rm1/name valuehadoop01:8088/value /property property nameyarn.resourcemanager.webapp.address.rm2/name valuehadoop02:8088/value /property !-- RM 依赖 ZooKeeper 完成选主 -- property nameyarn.resourcemanager.zk-address/name valuehadoop01:2181,hadoop02:2181,hadoop03:2181/value /property !-- 开启状态恢复切换后新 RM 能接管旧状态 -- property nameyarn.resourcemanager.recovery.enabled/name valuetrue/value /property !-- 启用 NodeManager 的辅助服务MapReduce 的 shuffle 依赖它 -- property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property !-- 日志聚合配合历史服务器查看日志 -- property nameyarn.log-aggregation-enable/name valuetrue/value /property property nameyarn.log-aggregation.retain-seconds/name value604800/value /property /configuration这里注意yarn.resourcemanager.cluster-id在同一个 HA 组内必须一致否则两个 RM 无法确认彼此属于同一集群。另外NodeManager 的 aux-services 不配置的话MapReduce 的 Map 输出无法传输给 Reduce任务会卡在 shuffle 阶段。4.5 mapred-site.xmlMapReduce 框架与历史服务器configuration !-- 指定 MR 运行在 yarn 上 -- property namemapreduce.framework.name/name valueyarn/value /property !-- 历史服务器地址用于查询已完成的作业 -- property namemapreduce.jobhistory.address/name valuehadoop04:10020/value /property !-- 历史服务器 Web UI -- property namemapreduce.jobhistory.webapp.address/name valuehadoop04:19888/value /property /configuration历史服务器在这套方案里单独放在 hadoop04是为了让主控节点轻量化。如果你机器紧张放在 hadoop02 上也完全可以只是要注意别让所有核心服务挤在一台。4.6 workers 文件声明 DataNode 部署范围$HADOOP_HOME/etc/hadoop/workers文件用于指定哪些节点启动 DataNodehadoop03 hadoop04 hadoop05这里不要写 hadoop01 和 hadoop02因为它们专职做 NameNode 和 ResourceManager。当然如果你机器少想额外增加数据节点也可以把 01、02 加进来当 DataNode但生产环境通常会让主控节点和存储节点分离。5. 集群启动的完整顺序格式化、同步元数据与常见首启报错5.1 启动顺序为什么不能乱第一次启动 HA 集群最容易出错的部分不是配置而是“顺序”。我见过很多人直接跑start-dfs.sh结果 NameNode 格式化的元数据没同步、JournalNode 为空、ZKFC 没起来报错五花八门。正确的首次启动顺序是启动 ZooKeeper 集群3 台在 3 台 JournalNode 节点分别启动 journalnode在 hadoop01 执行hdfs namenode -format格式化主 NameNode在 hadoop02 用hdfs namenode -bootstrapStandby同步元数据启动 hadoop01 的 NameNode 和两台 NameNode 节点上的 ZKFC启动 DataNode启动 YARN 组件RM、NodeManager启动历史服务器。5.2 JournalNode 与首个 NameNode 格式化在 hadoop03、hadoop04、hadoop05 上分别执行hdfs --daemon start journalnode用 jps 检查进程里应当看到JournalNode。然后回到 hadoop01执行格式化命令hdfs namenode -format格式化完成后检查/data/hadoop/tmp下是否生成了dfs/name和dfs/nameservice1之类目录确认元数据落盘。一个新手最容易犯的错格式化完成后直接对 hadoop02 也执行hdfs namenode -format。这会生成一个新的、独立的 namespace两个 Namenode 的 clusterId 不一样后面同步一定会失败。正确做法是用bootstrapStandby从主节点拉取元数据。5.3 bootstrapStandby 把元数据同步到备用节点在 hadoop02 上执行hdfs namenode -bootstrapStandby该命令会从shared.edits.dir的 JournalNode 集群读取命名空间状态并把它保存在本地的 dfs/name 目录中。执行之前务必确保 hadoop01 已经完成 format并且 JournalNode 已经启动否则它会提示找不到可用的 edit log。如果 bootstrapStandby 时报错提示storage directory already contains an unknown storage type多半是你之前曾手动格式化过 hadoop02。解决方法把/data/hadoop/tmp目录清空后重新执行。5.4 启动 NameNode 与 ZKFC然后拉起整个集群在 hadoop01 上启动 Active 侧的 NameNode 进程hdfs --daemon start namenode然后在 hadoop01 和 hadoop02 分别启动 ZKFChdfs --daemon start zkfcZKFC 启动后会立刻连接 ZooKeeper并尝试给对应 NameNode 注册锁。此时在 hadoop02 上也可以直接把 Standby NameNode 拉起来或者直接执行完整的脚本一次到位# 在 hadoop01 上执行 start-dfs.sh脚本会读取 workers 文件启动所有 DataNode同时启动 JournalNode 和 ZKFC如果还没启动。启动完成后用 jps 检查各节点进程hadoop01NameNode、DFSZKFailoverController、ResourceManager下一步、QuorumPeerMainhadoop02NameNode、DFSZKFailoverController、ResourceManager下一步、QuorumPeerMainhadoop03/04/05DataNode、JournalNode、QuorumPeerMain在这里我要特意强调一个高发问题如果 start-dfs.sh 执行时报“Cannot connect to journal node”或类似的连接 JournalNode 错误绝大多数是 JournalNode 没起全或防火墙没关。先逐台 jps 确认三个 JournalNode 都在再排查防火墙不要一上来就怀疑配置写错。5.5 启动 YARN 与历史服务器接着在 hadoop01 上执行start-yarn.sh脚本会读取 yarn-site.xml 中的 RM 配置在 hadoop01 和 hadoop02 分别启动 rm1 和 rm2并读取 workers 文件启动 NodeManager。最后在 hadoop04 上启动历史服务器mapred --daemon start historyserver全部启动完成后一个完整的 HA 集群就站起来了。接下来进入验证环节这一步千万别省。6. 高可用验证与手动故障切换检验 HA 不是“配了就完事”6.1 进程和端口层面的检查清单走到这一步你已经完成了 90% 的工作但还差关键的验证。我列一张检查表你可以照着逐项打勾检查项命令/地址预期结果HDFS 主备状态hdfs haadmin -getAllServiceState一个 active一个 standbyYARN RM 状态yarn rmadmin -getServiceState rm1输出 active/standbyWeb UI 主 NameNodehttp://hadoop01:9870正常显示且有 Standby 提示Web UI RMhttp://hadoop01:8088显示 Active 的 RM 节点历史服务器 UIhttp://hadoop04:19888正常打开DataNode 数量hdfs dfsadmin -report3 个 DataNode 可见hdfs haadmin -getAllServiceState是检查 HA 是否生效的最直观手段[hdfshadoop01 ~]$ hdfs haadmin -getAllServiceState hadoop01:8020 active hadoop02:8020 standby6.2 手动故障切换演练kill 掉 Active 进程配置了 automatic-failover 之后理论上无需人工干预但我强烈建议你主动演练一次故障切换确认 ZKFC 能正常接管。方案如下在 hadoop01 上 kill 掉 Active NameNode 进程kill -9 $(jps | grep NameNode | awk {print $1})等待大约 30 秒取决于 ZKFC 会话超时时间再查询状态hdfs haadmin -getAllServiceState正常情况下 hadoop02 的 NameNode 会自动从 standby 变成 active。也可以在故障切换后用hdfs dfs -ls /测试读写是否正常。手动触发的另一种方式是通过命令在不 kill 进程的情况下切换hdfs haadmin -failover hadoop01 hadoop02这个命令会把 Active 身份强制交给 hadoop02。注意执行 failover 前务必确保 hadoop01 真的有能力退出 Active否则脑裂风险会让共享编辑日志写入冲突。6.3 客户端行为与 ZKFC 超时参数这里要补充一个生产经验自动切换的时效性与 ZKFC 的 session timeout 强相关。如果 ZooKeeper 的tickTime是默认 2000msZKFC 默认超时大约是 10 秒左右。测试时你会发现切换并不算“秒级”大概要十几秒这个正常不用怀疑配置。但如果你发现切换后客户端仍然一直报“Connection refused”请检查客户端是否配置了ipc.client.connect.timeout和故障代理重试次数。默认的重试次数可能不够导致客户端在第一次连接失败后直接异常退出。我通常会在 core-site.xml 里补上property nameipc.client.connect.max.retries.on.timeouts/name value10/value /property这样在 HA 切换的几十秒窗口内客户端不会直接崩溃。6.4 ResourceManager 的切换验证RM 的切换验证相对简单kill 掉 hadoop01 的 ResourceManager 进程kill -9 $(jps | grep ResourceManager | awk {print $1})然后查询yarn rmadmin -getServiceState rm2如果 hadoop02 的 RM 显示 active说明 RM HA 正常。之后如果你再跑一个 MapReduce 作业可以看到任务能正常提交和完成。7. 历史服务器与日志聚合排障时最难少的辅助设施7.1 为什么历史服务器在 HA 集群里那么重要很多新手搭完 Hadoop 就完事觉得历史服务器可有可无。但实际使用中散落在各个 NodeManager 上的日志几乎是排查失败任务的第一手资料没有历史服务器你只能 ssh 到每一台节点上翻 yarn 聚合目录费时又痛苦。历史服务器解决两个问题作业跑完后作业详情可以在 Web UI 上回看跑完的 MR 任务在 ResourceManager 页面会从“RUNNING”转为“History”点击进去能看到 Map/Reduce 各阶段的指标日志集中归档。配合yarn.log-aggregation-enabletrue容器日志会上传到 HDFS 特定目录通过历史服务器 Web UI 直接浏览不再需要逐台登录。7.2 历史服务器配置与验证历史服务器只有三个关键配置前面 mapred-site.xml 已经写好了mapreduce.jobhistory.address和mapreduce.jobhistory.webapp.address。启动方式mapred --daemon start historyserver确认进程存在后打开http://hadoop04:19888就能看到历史任务页面。之后随便跑一个测试任务比如自带 wordcount 或用 Pi 算法验证hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.4.jar pi 4 1000任务跑完后去历史服务器 UI 看这个作业的记录是否存在。如果看到“Application History”里能点开作业说明整套链路通了。7.3 一个容易漏掉的细节MapReduce 作业的历史数据存储在 fs.defaultFS历史服务器默认会把完成的作业归档到 HDFS 的/tmp/hadoop-yarn/staging/history/下。在 HA 集群里它依赖fs.defaultFS指向 HDFS所以历史服务器要能读取hdfs://hacluster的元数据。如果历史服务器启动时报无法访问 HDFS多半是 core-site.xml 里fs.defaultFS没有配置成 HA 地址或者没有把这份配置同步到 hadoop04。另一个常见问题跑完的任务在历史服务器页面显示“UNKNOWN”这是 YARN 的 Timeline Server 和 History Server 之间状态不同步导致的。最简单的规避方案是配置yarn.timeline-service.enabledfalse或者接受这种显示差异——它不影响任务实际结果查看。8. 运维中踩过的坑从“起不来”到“悄悄切主”8.1 不可重复格式化元数据一致性是红线在 HA 集群里“格式化”这件事只能做一次。如果因为某种原因想推倒重来必须把所有节点的dfs/name、dfs/journal、/data/hadoop/journal目录全部清空同时清空 ZooKeeper 中 Hadoop 相关的 znodes否则会出现两个 NameNode 各持一个 clusterId 的情况状态看起来是 active/standby实际上根本无法同步 edits 日志。我同事第一次搭 HA 时就是没清 ZooKeeper 里残留的 HA 状态执行start-dfs.sh后 ZKFC 反复把 NameNode 踢来踢去日志里全是 “Failover failed”。最后我把客户端连接到 ZooKeeper删除/hadoop-ha/hacluster整个目录重新初始化才算平息。8.2 “双向免密”不到位导致的 fencing 失败sshfence 这种隔离方式依赖 SSH 登录对方机器执行 fuser。如果你只配置了主节点到备用节点的单向免密当备用节点需要隔离主节点时就会卡在“no passphrase”或“Host key verification failed”。这个问题很隐蔽因为第一次启动主备切换可能正好不需要隔离等到真正触发 failover 时才爆出来。解决方式# 在两台 NameNode 之间 hadoop01 - hadoop02 免密 hadoop02 - hadoop01 免密并且在/etc/ssh/sshd_config中允许 root 登录或者用部署用户免密同时把 StrictHostKeyChecking 设置为 no避免首次 SSH 询问确认导致脚本超时。8.3 JournalNode 说崩就崩先看磁盘和文件句柄JournalNode 进程挂掉的原因里磁盘写满占比最大。edit log 是连续写入的如果/data/hadoop/journal所在分区满了JournalNode 会直接异常退出紧接着 NameNode 报 “Unable to write edits to journal”。日常运维建议盯三个指标分区使用率控制在 80% 以下文件句柄数ulimit -n调到 65535 以上系统时间偏差建议启用 NTP 同步偏差超过 1 秒就可能引发同步异常。8.4 切主之后的“僵尸 ResourceManager”现象还有一种故障模式比较隐蔽Active RM 被 kill 或网络分区后备用 RM 成功接管但旧 RM 其实没死透。两个 RM 同时认为自己是 Active会导致客户端随机连接到一个“假主”提交任务后卡住不执行。这个场景我建议你直接看 YARN 日志定位是否出现Duplicate RMID或Unable to elect active。根本解法是配置yarn.resourcemanager.auto-recovery和 ZooKeeper 的隔离超时并严格保证 RM 进程被 kill 干净。在做故障演练时一定要 kill 进程而不是直接断网——断网会让新旧 RM 同时“存活”最容易诱发脑裂。8.5 日常巡检三个命令判断集群健康度集群搭好后不要等出故障再爬起来看。我在日常运维里固定保持三个巡检命令hdfs haadmin -getAllServiceState # 查看 NN 主备状态 yarn rmadmin -getServiceState rm1 # 查看 RM 状态 hdfs dfsadmin -report # 查看 DataNode 数量和容量如果某一天你发现 HA 集群“一切正常但任务跑得极慢”先看看是不是有节点 JVM 内存打满。NameNode 的内存通常给 8G~16GDataNode 给 4G~8G这些都要在hadoop-env.sh里显式设置默认参数在真实负载下顶不住。9. 最后分享一点个人建议把集群搭完后的“验证脚本”固化下来如果你照着前面步骤走正常半天到一天就能让 Hadoop 3.1.4 的完全分布式 HA 集群跑起来。但我最想提醒你的是搭起来只是第一步把“验证手段”固化成习惯才是长期收益。我现在每搭完一套 HA 集群都会做三件事写一个一屏的快捷检查脚本把第 6 节的检查项全部跑一遍输出状态摘要主动做一次hdfs haadmin -failover切换演练确认隔离机制确实能杀干净旧节点在/data/hadoop下留一份当次部署的配置版本备份改任何参数前先cp一份快照。这套集群能不能在生产环境扛住关键不在配置有多漂亮而在于你平时对“主备是否一致、日志是否正常滚动、磁盘是否够用”这三件事心里有没有数。每次出问题先查 ZooKeeper 的选举状态和 JournalNode 的磁盘用量大部分故障都能很快定位。希望你这次搭建少踩坑多跑几年不宕机。