资讯动态

Hadoop 3.x完全分布式集群HA高可用架构设计与部署实战

发布时间:2026/10/19 9:38:28 来源:尧图企业网站定制
1. 集群整体架构设计与选型思路1.1 为什么非要上完全分布式加HA单机伪分布式跑个Demo没问题但一旦数据量上来、任务并发变高单点故障就是悬在头顶的刀。NameNode挂了整个HDFS读不了也写不了ResourceManager挂了所有计算任务排队等死。这套方案的核心目标就一个让任何一个主控节点宕机时集群能在秒级到分钟级内自动恢复服务。我选的是Hadoop 3.x系列配合ZooKeeper 3.8.x原因很直接Hadoop 3对NameNode HA的支持已经非常成熟而且YARN的ResourceManager HA配置比2.x简洁不少。ZooKeeper在这里扮演两个角色——NameNode HA的ZKFC选举协调器以及YARN ResourceManager的Active-Standby状态存储。一套ZK集群同时服务两个HA体系资源利用率高运维也省心。节点规划上我用了5台机器3台跑ZK和JournalNode2台跑NameNode和ResourceManager。为什么是5台而不是3台因为ZK集群要求奇数节点3台刚好满足容错1台的要求而NameNode和ResourceManager各需要2台做HA对。如果预算紧张3台也能凑合——把NameNode、ResourceManager、ZK、JournalNode全混布但生产环境不建议这么干资源争抢和故障域重叠会让你排查问题排到怀疑人生。1.2 核心组件角色分配与端口规划先把角色分配表列清楚后面所有配置都围绕这张表展开节点主机名ZK角色NameNode角色JournalNodeResourceManagerDataNode/NodeManagernode01FollowerActive NN是Active RM是node02FollowerStandby NN是Standby RM是node03Leader否是否是node04Follower否否否是node05Follower否否否是端口方面NameNode的RPC端口用8020Web UI用9870ResourceManager的RPC用8032Web UI用8088JournalNode的RPC用8485ZK客户端端口2181。这些端口在防火墙策略里必须提前放行否则ZKFC选举时会因为连不上JournalNode而反复重试日志里全是Connection refused新手很容易卡在这一步。注意所有节点的hostname必须提前在/etc/hosts里配好并且保证互相能ping通。我见过有人用IP配HA结果ZKFC的自动故障转移死活不生效——因为Hadoop的HA配置里如果写IPZKFC在切换时无法正确解析目标节点的主机名导致fencing失败。1.3 为什么选QJM共享存储而不是NFSNameNode HA的共享编辑日志方案有两种QJM和NFS。我选QJM的原因有三第一QJM不需要额外搭建NFS服务少一个故障点第二QJM的JournalNode本身就是分布式设计容忍少数节点宕机第三QJM的写入延迟比NFS低因为它是并行写入多个JournalNode只要多数节点确认就返回成功。QJM的容错公式是允许宕机的JournalNode数量 (JournalNode总数 - 1) / 2。我配了3个JournalNode所以允许挂1台。如果配5个允许挂2台但写入延迟会略微增加因为需要等待更多节点确认。生产环境3个足够除非你的机房跨机架部署那建议5个。2. 基础环境准备与系统调优2.1 操作系统层面的必做项所有节点统一用CentOS 7.9或Ubuntu 20.04别混用。我踩过的坑CentOS和Ubuntu的默认文件句柄数、内核参数、甚至JDK的默认字符集都不一样混用会导致DataNode之间传输数据时出现莫名其妙的编码错误。关闭防火墙和SELinux是第一步但生产环境不能直接关防火墙得按端口放行。测试环境为了省事可以临时关闭systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config配置hosts和hostname每台机器执行hostnamectl set-hostname node01 cat /etc/hosts EOF 192.168.1.101 node01 192.168.1.102 node02 192.168.1.103 node03 192.168.1.104 node04 192.168.1.105 node05 EOF创建统一用户和目录我习惯用hadoop用户UID和GID在所有节点保持一致groupadd -g 1001 hadoop useradd -u 1001 -g hadoop -m hadoop echo hadoop:你的密码 | chpasswd配置SSH免密登录在node01上生成密钥对然后分发到所有节点su - hadoop ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id node01 ssh-copy-id node02 ssh-copy-id node03 ssh-copy-id node04 ssh-copy-id node05实操心得ssh-copy-id之后一定要手动ssh一遍每台机器第一次连接会提示确认指纹如果跳过这步后面启动集群时脚本会卡在yes/no交互上自动化脚本直接失败。2.2 JDK安装与JAVA_HOME的坑Hadoop 3.x要求JDK 8或JDK 11。我推荐JDK 8因为生态兼容性最好。安装路径统一为/usr/local/jdk1.8所有节点保持一致tar -zxvf jdk-8u351-linux-x64.tar.gz -C /usr/local/ mv /usr/local/jdk1.8.0_351 /usr/local/jdk1.8 cat /etc/profile EOF export JAVA_HOME/usr/local/jdk1.8 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar EOF source /etc/profile关键坑点Hadoop的hadoop-env.sh里必须显式指定JAVA_HOME不能依赖系统环境变量。因为Hadoop启动脚本在某些情况下不会加载/etc/profile导致找不到Javaecho export JAVA_HOME/usr/local/jdk1.8 $HADOOP_HOME/etc/hadoop/hadoop-env.sh2.3 ZooKeeper集群部署ZK集群是整套HA体系的基石必须先于Hadoop启动。在三台ZK节点上分别操作tar -zxvf apache-zookeeper-3.8.3-bin.tar.gz -C /opt/ mv /opt/apache-zookeeper-3.8.3-bin /opt/zookeeper mkdir -p /data/zookeeper/data mkdir -p /data/zookeeper/logs创建myid文件node01写1node02写2node03写3echo 1 /data/zookeeper/data/myid # node01执行 echo 2 /data/zookeeper/data/myid # node02执行 echo 3 /data/zookeeper/data/myid # node03执行配置zoo.cfgtickTime2000 initLimit10 syncLimit5 dataDir/data/zookeeper/data dataLogDir/data/zookeeper/logs clientPort2181 maxClientCnxns60 autopurge.snapRetainCount3 autopurge.purgeInterval1 server.1node01:2888:3888 server.2node02:2888:3888 server.3node03:2888:3888启动ZK集群/opt/zookeeper/bin/zkServer.sh start /opt/zookeeper/bin/zkServer.sh status三台都启动后应该看到一台Leader两台Follower。如果全是Looking状态检查myid文件内容和zoo.cfg里的server编号是否对应以及防火墙是否放行了2888和3888端口。注意ZK的dataDir目录权限必须是hadoop用户可写否则启动时报Permission denied。我习惯用chown -R hadoop:hadoop /data/zookeeper统一授权。3. Hadoop完全分布式核心配置3.1 core-site.xml的HA关键参数core-site.xml是所有Hadoop组件的公共配置HA相关的核心参数都在这里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 property nameha.zookeeper.session-timeout.ms/name value10000/value /property /configurationfs.defaultFS写的是mycluster而不是具体主机名这是HA的核心——客户端通过逻辑名称访问由ZKFC决定当前Active是谁。mycluster这个名字可以自定义但必须和hdfs-site.xml里的dfs.nameservices保持一致。ha.zookeeper.session-timeout.ms默认是5000毫秒我调到10000。原因如果ZK集群网络抖动超过5秒ZKFC会认为Active NameNode失联并触发切换但实际可能只是短暂网络问题。调到10秒能减少误切换代价是真实故障时切换慢5秒。这个取舍看你的业务容忍度。3.2 hdfs-site.xml的NameNode HA配置这是整个方案最核心的配置文件我逐段解释configuration !-- 命名服务逻辑名称 -- property namedfs.nameservices/name valuemycluster/value /property !-- 两个NameNode的ID -- property namedfs.ha.namenodes.mycluster/name valuenn1,nn2/value /property !-- nn1的RPC和Web地址 -- property namedfs.namenode.rpc-address.mycluster.nn1/name valuenode01:8020/value /property property namedfs.namenode.http-address.mycluster.nn1/name valuenode01:9870/value /property !-- nn2的RPC和Web地址 -- property namedfs.namenode.rpc-address.mycluster.nn2/name valuenode02:8020/value /property property namedfs.namenode.http-address.mycluster.nn2/name valuenode02:9870/value /property !-- JournalNode共享编辑日志地址 -- property namedfs.namenode.shared.edits.dir/name valueqjournal://node01:8485;node02:8485;node03:8485/mycluster/value /property !-- JournalNode本地数据目录 -- property namedfs.journalnode.edits.dir/name value/data/hadoop/journalnode/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 /property !-- fencing隔离方法 -- property namedfs.ha.fencing.methods/name valuesshfence/value /property property namedfs.ha.fencing.ssh.private-key-files/name value/home/hadoop/.ssh/id_rsa/value /property property namedfs.ha.fencing.ssh.connect-timeout/name value30000/value /property !-- 副本数 -- property namedfs.replication/name value3/value /property !-- NameNode数据目录 -- property namedfs.namenode.name.dir/name value/data/hadoop/namenode/value /property property namedfs.datanode.data.dir/name value/data/hadoop/datanode/value /property /configurationfencing机制必须配。sshfence的作用是当ZKFC决定切换时先SSH到旧的Active节点执行kill命令确保旧的NameNode进程彻底死掉防止脑裂。如果不配fencing旧Active可能还在写JournalNode新Active也写编辑日志就乱了。实操心得sshfence要求从Active节点能免密SSH到Standby节点反过来也要。我建议所有节点之间两两免密省得后面出问题。另外dfs.ha.fencing.ssh.connect-timeout设30秒太短了SSH还没连上就超时切换失败。3.3 yarn-site.xml的ResourceManager HA配置YARN的HA配置比HDFS简单因为ResourceManager没有共享编辑日志状态直接存在ZK里configuration !-- ResourceManager HA开关 -- property nameyarn.resourcemanager.ha.enabled/name valuetrue/value /property !-- RM集群ID -- property nameyarn.resourcemanager.cluster-id/name valueyarn-cluster/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 property nameyarn.resourcemanager.webapp.address.rm1/name valuenode01:8088/value /property !-- rm2地址 -- property nameyarn.resourcemanager.hostname.rm2/name valuenode02/value /property property nameyarn.resourcemanager.webapp.address.rm2/name valuenode02:8088/value /property !-- ZK状态存储 -- property nameyarn.resourcemanager.zk-address/name valuenode01:2181,node02:2181,node03:2181/value /property property nameyarn.resourcemanager.recovery.enabled/name valuetrue/value /property property nameyarn.resourcemanager.store.class/name valueorg.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore/value /property !-- NodeManager辅助服务 -- 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.nodemanager.remote-app-log-dir/name value/tmp/logs/value /property /configurationyarn.resourcemanager.recovery.enabled必须为true否则RM重启后所有运行中的Application状态丢失正在跑的任务全部失败。ZKRMStateStore把Application状态、Token、队列信息全存ZK里切换后新Active RM能从ZK恢复状态。3.4 workers文件与分发配置workers文件列出所有DataNode和NodeManager节点cat $HADOOP_HOME/etc/hadoop/workers EOF node01 node02 node03 node04 node05 EOF然后把配置好的Hadoop目录分发到所有节点for i in node02 node03 node04 node05; do scp -r $HADOOP_HOME $i:$HADOOP_HOME scp /etc/profile $i:/etc/profile done注意分发后每台机器都要source /etc/profile否则hadoop命令找不到。我习惯在分发脚本最后加一句ssh $i source /etc/profile。4. 集群启动流程与HA验证4.1 首次启动的严格顺序启动顺序错了会导致各种诡异问题我总结的标准流程是第一步启动ZK集群三台ZK节点/opt/zookeeper/bin/zkServer.sh start确认一台Leader两台Follower后再进行下一步。第二步启动JournalNode三台JournalNode节点hdfs --daemon start journalnode第三步格式化NameNode仅在node01执行hdfs namenode -format第四步启动node01的NameNodehdfs --daemon start namenode第五步同步node02的NameNode元数据hdfs namenode -bootstrapStandby这一步从node01的Active NameNode拉取最新的fsimage和编辑日志确保两个NameNode元数据一致。第六步格式化ZKFC仅在node01执行hdfs zkfc -formatZK这一步在ZK里创建HA相关的znodeZKFC启动后会往这些znode写状态。第七步启动整个HDFS集群start-dfs.sh这个脚本会自动在所有节点启动DataNode在node01和node02启动NameNode和ZKFC。第八步启动YARNstart-yarn.sh在node01启动ResourceManager其他节点启动NodeManager。然后手动在node02启动Standby ResourceManageryarn --daemon start resourcemanager4.2 HA自动切换验证方法验证NameNode HA是否生效最直接的方法是kill掉Active NameNode进程看Standby是否自动接管# 查看当前Active hdfs haadmin -getServiceState nn1 hdfs haadmin -getServiceState nn2 # 手动kill Active kill -9 $(jps | grep NameNode | awk {print $1}) # 等待10秒后查看状态 hdfs haadmin -getServiceState nn1 hdfs haadmin -getServiceState nn2如果配置正确原来的Standby会变成Active原来的Active变成Standby进程已死。ZKFC的日志在$HADOOP_HOME/logs/hadoop-hadoop-zkfc-*.log切换过程的每一步都有记录。YARN的HA验证类似yarn rmadmin -getServiceState rm1 yarn rmadmin -getServiceState rm2kill掉Active RM后Standby RM应该在30秒内接管。YARN的切换比HDFS慢因为RM需要从ZK恢复状态。4.3 常见故障与排查速查表现象可能原因排查方法解决方案ZKFC启动后两个NN都是StandbyZK里没有Active节点查看ZKFC日志检查ha.zookeeper.quorum配置确认ZK可连切换时卡在fencingSSH免密未配好手动ssh测试配置所有节点两两免密JournalNode写入失败磁盘满或权限不对df -h和ls -la清理磁盘chown hadoop:hadoopRM切换后任务全部失败recovery未开启查看yarn-site.xml设置recovery.enabled为trueDataNode无法注册workers文件未分发检查各节点workers重新分发并重启Web UI显示Standby正常现象访问Active的9870用hdfs haadmin查Active实操心得ZKFC的日志级别默认是INFO排查问题时建议临时调到DEBUG。修改log4j.properties里的log4j.logger.org.apache.hadoop.haDEBUG重启ZKFC后日志会详细到每一步选举和fencing操作。5. 生产环境调优与运维经验5.1 JVM堆内存与GC调优NameNode的堆内存默认是1000MB生产环境根本不够。我管理的集群有5000万文件NameNode堆设了16GB。计算公式每100万文件约需1GB堆内存再留50%余量。在hadoop-env.sh里调整export HDFS_NAMENODE_OPTS-Xmx16g -Xms16g -XX:UseG1GC -XX:MaxGCPauseMillis200 export HDFS_JOURNALNODE_OPTS-Xmx4g -Xms4g -XX:UseG1GC export YARN_RESOURCEMANAGER_OPTS-Xmx8g -Xms8g -XX:UseG1GCG1GC是Hadoop 3.x的推荐GC相比CMS能更好地控制停顿时间。MaxGCPauseMillis设200毫秒NameNode的GC停顿超过这个值客户端请求就会超时。5.2 机架感知配置生产环境必须配机架感知否则所有副本可能落在同一个机架机架断电数据全丢。配置方法# 在core-site.xml添加 property namenet.topology.script.file.name/name value/etc/hadoop/rack.sh/value /propertyrack.sh脚本根据IP返回机架名#!/bin/bash HOST$1 case $HOST in 192.168.1.10[1-3]) echo /rack1 ;; 192.168.1.10[4-5]) echo /rack2 ;; *) echo /default-rack ;; esac配好后用hdfs dfsadmin -printTopology验证。5.3 日常巡检清单我每天早上花10分钟跑一遍这些检查hdfs haadmin -getServiceState nn1和nn2确认一主一备yarn rmadmin -getServiceState rm1和rm2确认一主一备hdfs dfsadmin -report看DataNode数量和容量yarn node -list看NodeManager状态zkServer.sh status确认ZK集群健康检查NameNode和ResourceManager的GC日志看Full GC频率注意如果发现频繁Full GC先别急着加堆内存用jmap dump堆快照分析是不是有大量小文件或者泄漏。我遇到过NameNode堆里堆积了几百万个INode对象原因是某个任务疯狂创建小文件清理后GC恢复正常。5.4 扩容与缩容操作扩容DataNode很简单新节点装好Hadoop配好hosts和SSH把workers文件加上新节点然后在新节点执行hdfs --daemon start datanode和yarn --daemon start nodemanager。NameNode会自动识别新节点并开始分配数据块。缩容要小心先用hdfs dfsadmin -refreshNodes配合exclude文件把节点标记为Decommission等数据块全部迁移完hdfs dfsadmin -report里该节点显示Decommissioned再停进程。直接kill进程会导致数据块副本不足触发大量复制流量。这套集群我跑了两年多经历过NameNode进程崩溃、ZK集群网络分区、JournalNode磁盘写满等各种故障HA机制每次都成功接管业务侧最多感知到几十秒的抖动。核心经验就一条HA不是配完就完事定期演练切换、监控ZKFC和JournalNode的健康状态才能保证真出故障时它真的能顶上。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑