Hadoop的高可用(HA,High Availability)机制主要解决的是HDFS中NameNode的单点故障问题。在没有HA的情况下,NameNode一旦挂掉,整个文件系统将无法访问,集群里的所有计算任务都会受到影响。本文将从架构原理、环境准备、配置修改、启动验证和常见疑问五个方面,把Hadoop高可用的搭建过程完整过一遍,适合刚接触Hadoop的同学跟着操作。

一、Hadoop高可用的核心原理
HDFS高可用的基本思路是:在一个集群中运行两个NameNode,一个是Active状态(对外提供服务),另一个是Standby状态(随时待命)。两个节点之间通过一组JournalNode同步元数据编辑日志,当Active节点写入一个editlog时,Standby节点会实时读取这些日志并应用到自己的内存命名空间中,从而保证两者的元数据几乎一致。
要实现自动故障切换,还需要两个关键组件。第一个是ZooKeeper集群,它负责维护集群状态和进行选主;第二个是ZKFC(ZKFailoverController),每个NameNode节点上运行一个ZKfc进程,它持续监控本机NameNode的健康状况。当Active节点的ZKFC检测到NameNode异常时,会主动放弃ZooKeeper上的锁,Standby节点的ZKFC抢到锁之后,会先把原Active节点隔离(防止脑裂),再将Standby切换为Active。
JournalNode通常部署奇数个,最少3个。因为写入editlog时需要半数以上的JournalNode确认才算成功,3个节点可以容忍1个挂掉。这也是为什么JournalNode一般和ZooKeeper部署在相同的机器上,两者对节点数量的要求一致。
二、环境规划与准备工作
假设我们用5台机器搭建一个测试集群,规划如下:node1和node2部署NameNode和ZKFC,node1、node2、node3部署JournalNode,三台机器同时部署ZooKeeper,node3、node4、node5部署DataNode,ResourceManager也部署在node1和node2上实现YARN的高可用。操作系统建议使用CentOS 7或Ubuntu 20.04以上版本,JDK版本选择1.8,Hadoop版本推荐3.1.3或3.3.x,ZooKeeper使用3.5.x以上稳定版。
基础环境配置有几步必须做。首先是修改所有节点的hosts文件,把主机名和IP的映射写进去,保证节点之间可以用主机名互相访问:
192.168.10.101 node1 192.168.10.102 node2 192.168.10.103 node3 192.168.10.104 node4 192.168.10.105 node5
其次是配置SSH免密登录。因为启动集群脚本时,node1要能免密登录到所有节点(包括自己),两个NameNode之间还要能互相免密,否则ZKFC在执行隔离操作时会失败。执行以下命令生成密钥并分发公钥:
ssh-keygen -t rsa ssh-copy-id node1 ssh-copy-id node2 ssh-copy-id node3 ssh-copy-id node4 ssh-copy-id node5
最后关闭所有节点的防火墙和SELinux,设置好JAVA_HOME环境变量。这些步骤看似简单,但绝大多数启动失败的案例都出在免密登录和环境变量上,建议每一步都验证通过后再往下走。
三、核心配置文件详解
Hadoop HA的配置主要集中在core-site.xml和hdfs-site.xml两个文件里。先看core-site.xml,这里指定NameService的逻辑名称和临时目录:
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/module/hadoop-3.3.4/data</value>
</property>
<property>
<name>ha.zookeeper.quorum</name>
<value>node1:2181,node2:2181,node3:2181</value>
</property>
</configuration>fs.defaultFS的值不再是具体的某台机器,而是逻辑名称mycluster,客户端访问时只需要连接这个逻辑名,故障切换对客户端是透明的。hdfs-site.xml是重头戏,需要配置两个NameNode的地址、JournalNode的地址和故障切换方式:
<configuration>
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>node1:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>node2:8020</value>
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node1:8485;node2:8485;node3:8485/mycluster</value>
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
</configuration>其中fencing配置特别容易出错。sshfence表示新Active在切换前先通过SSH登录旧Active节点并杀掉NameNode进程,这就要求node1和node2之间必须互相免密,而且私钥路径要写对。如果用户不是root,路径要改成对应用户的家目录。配置完成后用scp把整个Hadoop目录分发到其他节点,注意每个节点hadoop-env.sh里的JAVA_HOME都要检查一遍。
四、集群启动与故障切换验证
启动顺序有讲究,必须先启动ZooKeeper集群,在每个ZooKeeper节点上执行:
zkServer.sh start zkServer.sh status # 确认一个leader两个follower
然后启动JournalNode。第一次格式化集群的完整流程是:先在每个JournalNode节点执行hadoop-daemon.sh start journalnode,接着在node1上格式化并启动NameNode:
hdfs namenode -format hadoop-daemon.sh start namenode # 在node2上拉取node1的元数据 hdfs namenode -bootstrapStandby hadoop-daemon.sh start namenode
两个NameNode都起来之后,初始化ZKFC的状态(只在其中一个节点执行一次):
hdfs zkfc -formatZK start-dfs.sh start-yarn.sh
验证HA是否真正生效,最直接的办法是手动制造故障。先用hdfs haadmin -getAllServiceState确认node1是active,然后直接kill掉node1的NameNode进程,观察Web页面,正常情况下几秒内node2就会变成active。再把node1的NameNode启动起来,它会自动以standby身份加入集群。如果切换不生效,优先检查ZKFC进程是否存在、ZooKeeper连接是否正常。
五、常见疑问与踩坑解答
第一个高频问题:为什么切换后出现两个Active,也就是脑裂?这通常是因为fencing失败,新Active无法杀死旧Active。解决办法是确认两个NameNode之间SSH免密正常、私钥路径配置正确,必要时可以增加shell脚本方式的fencing作为兜底。
第二个问题:DataNode全部启动失败怎么办?最常见的原因是集群ID不一致。多次执行hdfs namenode -format会生成新的clusterID,而DataNode记录的还是旧ID。处理办法是停掉集群,删除每个节点的data目录和logs目录,重新格式化一次再启动。所以格式化操作要谨慎,只做一次。
第三个问题:JournalNode挂掉一台会不会影响写入?只要存活的JournalNode超过半数(3台中至少2台),editlog写入就不受影响,但要及时修复挂掉的节点,不要长期带病运行。另外建议在HDFS上跑一段业务数据后,手动执行hdfs dfsadmin -safemode leave排查安全模式长时间退不出的情况,这多半是DataNode心跳异常导致的。
最后提醒一点,生产环境中ZooKeeper的5台部署、JournalNode的3台以上部署以及监控告警都应该提前规划好。高可用不是搭完就完事,定期做故障演练才能真正检验切换是否可靠。按照本文的步骤一步步来,遇到报错先看日志目录下的日志文件,大部分问题都能快速定位。
Hadoop高可用Hadoop集群搭建NameNode HA修改时间:2026-09-14 22:16:43