FEATURED · 精选文章

Hadoop高可用架构原理与实战:NameNode故障恢复与集群切换

发布时间 / 2026/9/9 17:14:28
来源 / 创域科博编辑部
栏目 / 资讯中心
Hadoop高可用架构原理与实战:NameNode故障恢复与集群切换 凌晨三点被监控电话叫醒这种事干过大数据的都懂。那一晚我值班HDFS的NameNode挂了整个数据平台停了将近四十分钟。调度任务全部卡死实时写入断流报表查询一片超时业务方的电话一个接一个打过来。当时集群没有配置高可用HANameNode一死全集群瘫痪只能手动恢复元数据等fsimage和edits日志重建完成。那一晚上之后我花了整整两周时间把集群的HA架构重新搭了一遍从HDFS到YARN全部做了高可用改造期间把各种坑基本踩了个遍。这篇文章就是把那段实践整理出来讲清楚Hadoop高可用架构设计背后的原理、配置步骤和故障排查方法给正准备上生产集群、或者正在准备大数据架构面试的朋友做一个参考。1. 高可用到底在解决什么问题1.1 先搞清楚HA保护的是“状态”不是“节点”很多初学者对高可用的理解停留在“多部署一台机器挂了就切换”但真正做架构设计的时候你会发现问题远没有这么简单。Hadoop早期版本的HDFS只有一个NameNode它维护整个文件系统的目录树和文件与数据块的映射关系所有元数据都存放在内存里相当于整个集群的“大脑”。这个大脑一旦宕机集群里其余上千个DataNode都还在但客户端根本不知道文件被切成了多少块、每一块存在哪台机器上整个HDFS就变成了一堆散落的硬盘。传统的恢复手段是依赖SecondaryNameNode。这个名字太有误导性了它根本不是NameNode的备份节点它的作用只是定期从NameNode拉取fsimage和edits日志进行合并帮NameNode减轻压力。一旦NameNode真挂了你只能把SecondaryNameNode上的元数据拷贝回来加上NameNode本地残留的edits日志手工合并再重启。这个过程短则十几分钟长则一两个小时期间整个集群对外不可用。更麻烦的是如果NameNode机器磁盘损坏连本地日志都丢了那恢复起来就是噩梦。所以HA要解决的核心问题不是“再找一台机器顶上”而是“如何把NameNode的状态实时地、一致地同步到另一台机器上”。状态是什么就是文件系统元数据。只有备节点拿到完整且一致的状态才有资格在主节点故障时无缝接管。这里有两个关键词完整、一致。完整意味着不能只同步fsimage还必须同步从上次checkpoint以来的所有操作记录一致意味着两边看到的文件系统视图必须完全一样不能出现主节点写了文件A、备节点不知道的情况。为了做到这一点Hadoop引入了JournalNode也就是QJMQuorum Journal Manager仲裁日志管理器方案后面我会详细拆解这个机制。生活里有个很好的类比可以把NameNode理解成一本日记每天都在记录文件系统里发生的所有事情。HA要做的事情就是你每写一行旁边那个人立刻照着抄一行。平时他就在那里等着你一旦出事他拿起那本抄好的日记就能继续写。但这里有个关键问题怎么保证同一时间只有一个人在写日记如果两个人都以为自己是“正主”同时往日记里写内容那整个系统就全乱了这个现象在分布式系统里叫“脑裂”HA设计里绕不开它也是面试官最爱问的点。1.2 架构里都有谁在干活一个完整可用的Hadoop HA集群涉及的角色远不止两个NameNode。我用一张表把参与方列清楚这样后面看配置的时候不会迷路。角色数量建议职责挂了会怎样Active NameNode1对外提供元数据读写服务写edits日志触发自动切换Standby NameNode1持续同步edits日志内存中维护元数据随时准备接管不影响尽快修复即可JournalNode3或5存储edits日志通过QJM协议保证多数派写入少于多数派时NameNode写edits会失败Zookeeper3或5分布式协调保存锁节点参与选主多数派存活即可挂少数不影响ZKFCDFSZKFailoverController每个NameNode节点各1个监控NameNode健康状态维护ZK锁执行fencing所在节点的主NameNode无法自动切换ResourceManager2YARN资源调度Active/Standby模式触发RM自动切换DataNode / NodeManager多个存储数据块、执行计算任务各自有容错机制不直接影响HA注意ZKFC虽然名字里带“ZK”但它是HDFS自带的小进程不是Zookeeper服务端的进程。它部署在NameNode所在的物理机上负责做健康检查和故障转移。很多人在部署的时候会漏掉ZKFC导致NameNode挂了之后完全不触发自动切换这个坑后面会细说。1.3 结合业务场景选哪种HA方案HA方案不是越复杂越好要结合集群规模、业务重要程度和运维成本来选。如果你只是搭一套测试环境学习Hadoop那就没必要上HA一台NameNode加一个SecondaryNameNode就够了省心省事。但如果集群要承载生产任务哪怕只是几十个节点的中小集群我都建议至少把双NameNodeQJM的HA做上去因为停机代价远大于配置成本。关于YARN的HA很多团队会忽略。他们觉得HDFS做HA就够了YARN挂了重启一下就行。但如果你跑的是离线批处理任务RM挂了会导致所有正在运行的任务状态丢失作业要么失败要么需要手动重试同样会造成大范围影响。所以在生产环境里我建议HDFS和YARN的高可用一起配。已经有不少线上事故是HDFS好好的RM挂了整个调度层瘫痪排查半天才发现RM没有配HA。另外还有一个方案叫HDFS Federation联邦它是为了解决NameNode内存瓶颈问题把文件系统目录切分成多个命名空间每个命名空间由独立的NameNode管理。联邦和HA是可以叠加使用的比如两个NameNode组成一个nameservice做HA另两个NameNode组成另一个nameservice做HA。如果你的集群规模到了几亿甚至几十亿文件的级别单NameNode内存吃紧就得考虑联邦方案。但联邦会引入跨命名空间数据迁移的问题架构复杂度会明显上升一般中小公司用不到这里就不展开细讲了。2. 核心机制拆解NameNode与ResourceManager如何实现无缝切换2.1 NameNode HA的底座QJM共享edits日志NameNode内存里的文件系统元数据是存在内存中的但所有修改操作都会先追加写入edits日志。HA架构里这些edits日志不再写到NameNode本地磁盘而是通过QJM协议发给一组JournalNode。Active NameNode向所有JournalNode并发写同一批edits只要大多数超过一半JournalNode返回写入成功就认为这次写操作已经提交。这里面的逻辑跟Raft协议很像核心思想就是“多数派”。假设有3个JournalNode最多允许1个故障如果有5个最多允许2个故障。JournalNode越多容错能力越强但同步延迟也会有所增加所以生产环境最常见的选择是3个或者5个很少用4个因为4个跟3个的容错能力一样都只能坏1个成本还更高。Standby NameNode做的事情是什么呢它持续从JournalNode读取edits日志回放到自己的内存中让自己的元数据状态无限接近Active节点。这里有一个很多教程没讲清楚的细节Standby节点并不是等Active完全写完才去读而是做“无缝跟踪”。它维护一个transaction ID的游标从JournalNode上不断拉取新产生的edits并应用因此正常情况下Standby的内存状态与Active的差距非常小。当Active故障时Standby只需要把最后几条没有同步完的edits补上就能接管服务。这个“差距”就决定了HA的RPO恢复点目标——理论上最多丢失几条尚未同步的edits但在多数派机制下Active写入成功的那部分edits一定已经存在于多数JournalNode上所以Standby一定可以读到实际场景下几乎可以做到零丢失。为什么不用共享存储方案这也是很多刚接触HA的人会问的。早期Hadoop确实支持通过NFS或者共享磁盘来做共享edits目录我在测试环境也试过。NFS的问题在于它本身是一个单点NFS服务器挂了两个NameNode都写不了edits整个集群等于瘫痪HA变成了单点故障的放大器。另外NFS在高并发写入下延迟不稳定容易成为性能瓶颈而且没法做多副本容错。QJM方案用普通的本地磁盘就能组一套JournalNode集群本身就是多副本的故障域被分散到多台机器上这才是真正的“高可用”。2.2 自动切换的真正执行者ZKFC与Fencing两个NameNode一个Active一个Standby谁来决定什么时候切换答案是ZKFC它跑在每个NameNode所在的机器上是独立于NameNode的Java进程。总结下来它干三件事。第一健康监控。ZKFC定期向本机的NameNode发送健康检查命令如果NameNode进程异常、JVM频繁Full GC导致长时间无响应或者机器本身出现故障ZKFC就会判定NameNode不健康。第二Zookeeper选主。正常工作时Active节点的ZKFC会在Zookeeper里持有一个锁节点类似临时节点Standby节点的ZKFC一直在尝试获取这个锁。一旦Active节点故障它的ZKFC进程也会跟着死掉或主动释放锁节点Zookeeper检测到临时节点消失后Standby节点的ZKFC就能立刻抢到锁完成“夺权”。第三执行fencing隔离。这一步是防止脑裂的关键。假设Active节点不是真的宕机而是卡死了但进程还在网络闪断导致ZKFC和Zookeeper之间失去连接。此时Zookeeper判定锁超时把锁释放了Standby节点抢到锁准备接管。但如果Active节点恢复了它并不知道自己已经被“下台”还在继续写edits这时就有两台机器同时以Active自居数据就会错乱。Fencing的目的就是在Standby接管前把旧Active节点彻底“干掉”手段包括通过SSH登录旧Active机器杀掉NameNode进程、调用指定的隔离脚本、或者通过共享存储的锁机制强制旧节点退出。只有确保旧Active不再工作新Active才能安全接管。这个机制说明了为什么自动切换不能只靠“心跳”判断——正因为网络分区是分布式系统最棘手的问题所以才需要用一个外部仲裁者Zookeeper加上强制的隔离动作Fencing来保证“同一时刻只有一个主人”。2.3 ResourceManager HA与任务恢复YARN的ResourceManager是集群资源调度的大脑管理着所有NodeManager的资源报告、ApplicationMaster的注册信息、以及各种调度器状态。要对RM做高可用思路和NameNode类似也是Active/Standby模式但存储状态的方式有点不同它不依赖JournalNode而是通过RMStateStore把状态保存到Zookeeper或者LevelDB中。YARN HA的关键配置意图是这样的启用RM的自动故障转移后两个RM同时启动但只有一个处于Active状态。当Active RM故障时Standby RM通过Zookeeper竞选成为Active然后从RMStateStore恢复状态。注意这个“恢复”是有限度的它恢复的是应用的基本信息和计数器而不是每一个任务的执行细节。那些正在运行的ApplicationMaster会向新的RM重新注册如果ApplicationMaster本身也丢了任务进度那就需要上层的MapReduce或者Spark框架自己去做任务重放。这里有个容易被忽略的点RM故障切换期间已经提交但还没被调度执行的作业会短暂地“卡住”等新RM就绪后重新调度正在执行的任务可能会因为AM重新注册而出现短暂停顿但一般不会直接失败。所以YARN HA能做到的是让RM故障不导致整个集群的调度能力长时间中断而不是让所有任务无缝无感。设计高可用架构的时候要对业务方讲清楚这个预期不然会被人误以为RM挂了之后作业完全不受影响。2.4 存储与计算节点的高可用细节NameNode和ResourceManager的HA解决的是“大脑”高可用那么被管理的DataNode和NodeManager挂掉怎么办这两个角色本身不存“状态”容错方式就是靠冗余和重新调度。DataNode通过心跳向NameNode上报自己持有的数据块信息。如果一个DataNode超过10分钟没有心跳参数是dfs.namenode.heartbeat.recheck-interval和心跳超时时间配合计算NameNode就会判定该节点宕机然后检查它上面的块副本数是否低于配置的副本因子。默认副本数是3如果少了NameNode会调度其他活跃的DataNode从剩余副本中复制数据补足副本数量。这个复制过程是后台自动完成的不需要人工介入但会消耗一定的网络和磁盘IO所以大节点宕机后集群往往会有一段时间负载升高。NodeManager挂了的逻辑类似但它管理的是计算资源。NodeManager失联后ResourceManager会把它上面的所有Container标记为失败然后通知对应的ApplicationMaster重新申请资源、重跑任务。这里需要提醒的是如果你的任务没有做checkpoint或者不支持失败重试NodeManager一挂任务还是会失败。所以严格意义上讲计算节点的高可用不完全靠YARN本身还得靠上层任务框架和任务设计来兜底。还有一个经常被架构师忽略的层面机架感知。如果你把三个副本放在同一个机架的同一台交换机下面那交换机断电或者光模块故障三个副本同时丢失无论HDFS怎么自愈都救不回来。所以生产环境一定要配置机架感知脚本让Hadoop了解网络拓扑。副本放置策略默认是“第一个副本在客户端本地机架、第二个副本在同机架不同节点、第三个副本跨机架”这样任何一个机架级故障都不会导致数据全部丢失。配置机架感知的成本很低就是一个脚本加上拓扑信息的映射但收益是实实在在的故障域隔离这是HA架构在“数据冗余”层面最重要的一环。3. 实操从零搭建一套双NameNode HA集群3.1 节点规划与资源估算我平时指导团队搭集群最常遇到的第一个问题就是“我该准备几台机器”。这里我给出一个标准的生产环境小集群规划一共5台可以承载中等规模的离线数据处理任务。主机名IP规划部署角色nn110.0.0.11NameNode(Active), ZKFC, ResourceManager(Active), Zookeepernn210.0.0.12NameNode(Standby), ZKFC, ResourceManager(Standby), Zookeeperjn110.0.0.13JournalNode, Zookeeper, DataNode, NodeManagerdn110.0.0.14DataNode, NodeManagerdn210.0.0.15DataNode, NodeManager注意上表里nn1和nn2同时也是Zookeeper节点这没问题但Zookeeper的数据目录最好放在独立的磁盘分区上不要和NameNode元数据目录挤在一起。JournalNode建议放在独立的机器上至少不要和NameNode共用同一块物理磁盘否则NameNode的磁盘故障同样会拖垮JournalNode失去故障域隔离的意义。如果机器数量不够退而求其次把JournalNode放在DataNode节点的独立目录上也比全部堆在主节点要稳妥。资源估算方面NameNode的JVM堆内存是一个核心参数。经验上每100万个元数据文件/块对象大约需要1GB到2GB的堆内存。一个5000万文件的中等集群建议堆内存给到16GB到32GB。但注意JVM堆超过32GB后对象指针压缩会失效GC停顿会明显变大所以单个NameNode的堆尽量控制在32GB以内文件数再多就考虑联邦方案了。JournalNode默认堆内存1GB够用edits日志的写入是磁盘IO密集型的内存需求不高。Zookeeper的堆内存默认1GB通常够用但如果客户端连接数特别多可以提到2GB到4GB前提是不要随便改它的默认GC配置容易出现奇怪的性能问题。磁盘规划上DataNode多块盘建议直接用JBODJust a Bunch Of Disks模式不要做RAID。这个很多初学的人想不通磁盘坏了怎么办答案是HDFS本身有副本机制不需要RAID来提供冗余。RAID5在HDFS场景下反而会降低磁盘利用率重建时间也长完全是花冤枉钱。NameNode的元数据目录建议用RAID1或者交给云盘做冗余因为元数据的可靠性比性能更重要。3.2 环境准备与Zookeeper集群搭建开始配Hadoop之前基础环境要处理好这部分不能省否则后面排查问题会排查到怀疑人生。所有节点统一时间同步我用chrony就够了误差控制在毫秒级。配置各节点的hostname和/etc/hosts确保节点之间通过主机名互相解析。Hadoop各组件之间大量使用主机名通信如果解析有问题会出现各种诡异的超时报错。JDK用1.8同时配置好JAVA_HOME环境变量。配置SSH免密登录注意需要配置的是nn1到nn2、nn1到各JournalNode和DataNode的免密因为NameNode启动时要通过SSH远程启动其他节点的守护进程。很多教程直接让你配所有节点全互通那是图省事但生产环境里最小化授权才是更安全的做法。接下来搭Zookeeper下载解压后配置conf/zoo.cfg核心参数如下tickTime2000 initLimit10 syncLimit5 dataDir/data/zookeeper/data dataLogDir/data/zookeeper/logs clientPort2181 server.1nn1:2888:3888 server.2nn2:2888:3888 server.3jn1:2888:3888有几个细节必须注意。dataDir和dataLogDir要分开日志盘故障时不会影响数据文件。server.X里的X对应的是每台机器上myid文件的内容myid文件要放在dataDir目录下这个不要配错配错了Zookeeper会反复找leader找不到。端口规划上2181是客户端端口2888是集群内部通信端口3888是选举端口防火墙要全部放通。启动后使用zkServer.sh status检查正常情况下三个节点里一个leader两个follower。3.3 HDFS HA关键配置与启动顺序配置HDFS HA是整个过程的重点我直接给出核心的配置片段并逐项说明为什么这么配。core-site.xml的配置configuration property namefs.defaultFS/name valuehdfs://mycluster/value /property property nameha.zookeeper.quorum/name valuenn1:2181,nn2:2181,jn1:2181/value /property /configuration第一个配置把默认文件系统设置为一个逻辑名称mycluster这个名称是我们在hdfs-site.xml里定义的nameservice。第二个配置告诉Hadoop集群的Zookeeper地址列表ZKFC和自动故障转移都靠它。hdfs-site.xml的配置比较多我挑了最关键的几项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 valuenn1:8020/value /property property namedfs.namenode.rpc-address.mycluster.nn2/name valuenn2:8020/value /property property namedfs.namenode.http-address.mycluster.nn1/name valuenn1:9870/value /property property namedfs.namenode.http-address.mycluster.nn2/name valuenn2:9870/value /property property namedfs.namenode.shared.edits.dir/name valueqjournal://nn1:8485;nn2:8485;jn1:8485/mycluster/value /property 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 property namedfs.journalnode.edits.dir/name value/data/hadoop/journal/value /property /configuration这些配置里最容易被配错的是qjournal地址的格式。它的结构是qjournal://jn1:8485;jn2:8485;jn3:8485/nameserviceId注意中间用分号分隔最后跟的是nameservice名称必须和dfs.nameservices保持一致。dfs.journalnode.edits.dir是JournalNode本地存储edits日志的路径这个路径在三个JournalNode上都要创建并且要放在可靠磁盘上。配置完成后首次启动的顺序相当有讲究我列出标准流程在所有JournalNode节点上先启动journalnode进程hdfs --daemon start journalnode在nn1上执行格式化命令hdfs namenode -format这一步生成初始的命名空间和fsimage由于是首次部署需要把nn1的元数据同步到nn2在nn2上执行hdfs namenode -bootstrapStandby它会自动从nn1拉取最新的元数据如果启用了自动故障转移还需要初始化Zookeeper中的HA状态hdfs zkfc -formatZK这一步本质是往ZK里创建HA相关的znode在nn1上执行hdfs --daemon start namenode启动Active节点然后在nn2上执行同样的命令启动Standby节点分别启动两个节点的ZKFC进程hdfs --daemon start zkfc启动完成后用hdfs haadmin -getAllServiceState查看两个NameNode的状态正常情况下应该一个是active一个是standby。然后SSH到nn1执行kill -9杀掉NameNode进程模拟故障观察约10到20秒后nn2应该自动切换成active。这里能切换成功说明ZKFC、Zookeeper和fencing整体链路都是通的集群HA基本就绪。整个过程中最容易出的问题有两个。第一个是在格式化的时候先后对两台机器执行了hdfs namenode -format导致两个NameNode的namespaceID不一致它们连到同一组JournalNode时就会出现严重冲突。解决方式只能是把所有元数据和JournalNode的数据清空重新走一遍整个格式化流程非常痛苦。第二个是启动顺序不对你先启动了NameNode再启动JournalNodeNameNode启动时会因为连不上JournalNode而失败或者初始化共享edits目录失败。切记首次搭建时先起JournalNode再起NameNode。3.4 YARN HA配置与切换演练HDFS的HA搞定之后YARN HA就相对简单了都是依赖Zookeeper做选主和状态存储。先看yarn-site.xml里的核心配置property nameyarn.resourcemanager.ha.enabled/name valuetrue/value /property property nameyarn.resourcemanager.cluster-id/name valuemy-yarn-cluster/value /property property nameyarn.resourcemanager.ha.rm-ids/name valuerm1,rm2/value /property property nameyarn.resourcemanager.hostname.rm1/name valuenn1/value /property property nameyarn.resourcemanager.hostname.rm2/name valuenn2/value /property property nameyarn.resourcemanager.zk-address/name valuenn1:2181,nn2:2181,jn1: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 property nameyarn.resourcemanager.ha.automatic-failover.enabled/name valuetrue/value /property property nameyarn.resourcemanager.ha.automatic-failover.embedded/name valuetrue/value /property /configuration这里有两个容易被忽略的点。第一个是yarn.resourcemanager.recovery.enabled必须配置为true否则RM的Standby即使抢到了主控权也无法从状态存储里恢复应用信息切换后所有应用的状态都会丢失。第二个是automatic-failover.embedded这个参数它默认就是true代表以嵌入式的方式在RM进程内部跑一个选主客户端不需要像HDFS那样单独启动ZKFC进程。很多人会误以为YARN也要单独启动一个类似ZKFC的进程其实不需要RM进程内部已经把这个事情做掉了。启动方式很简单在nn1上执行yarn --daemon start resourcemanager在nn2上执行同样的命令。然后通过yarn rmadmin -getServiceState rm1查看状态。想让RM切换可以直接杀掉Active RM进程观察Standby RM是否自动变成active。切换完成后新Active RM会从Zookeeper里恢复之前提交的应用状态正在运行的任务会经历短暂的“失联”然后恢复。3.5 集群扩容与均衡的实操经验集群上线运行半年后存储容量不够了要给HDFS扩容时操作上并不复杂但有几个隐藏的坑。新节点配置好Hadoop和JDK把core-site.xml、hdfs-site.xml、yarn-site.xml等配置文件从旧节点拷贝过来确保完全一致然后启动DataNode和NodeManager。启动后执行hdfs dfsadmin -report如果新节点的Capacity正常显示说明它已经被NameNode纳管。接下来一个常见问题是新节点加入后数据并不会自动往它上面迁移所有新写入的数据可能会继续落在旧节点上导致新节点磁盘紧张、旧节点磁盘宽松分布严重不均衡。这时需要手动执行均衡命令hdfs balancer -threshold 10 -bandwidth 104857600threshold参数表示允许的磁盘使用率偏差百分比bandwidth是均衡过程允许占用的网络带宽单位是字节每秒。上面这个例子就是允许偏差10%带宽最多100MB/s。我一般建议在业务低峰期跑均衡任务因为balancer本质上是在节点之间移动数据块会占用大量网络和磁盘IO跑得太猛会把在线业务的延迟打上去。这里还有一个更为隐蔽但经常在面试中被问到的点扩容一个新节点后如果没配置机架感知就启动DataNode新节点的副本放置将不遵循多机架策略三个副本可能全部落在同一个机架上。一旦这个机架发生物理故障数据就全丢了。所以先配置好机架感知再扩容这个顺序不要反过来。4. 常见问题与故障排查实录4.1 高频故障速查表下面这张表是我这几年在HA集群运维里遇到的高频问题整理成速查表可以直接收藏起来。故障现象可能原因排查命令与手段Active NameNode频繁切换网络抖动、ZKFC健康检查超时、NameNode Full GC过长看ZKFC日志检查GC时间ping对端节点自动failover没有生效ZKFC进程没启动、ZK锁节点异常、fencing脚本失败用hdfs haadmin -getAllServiceState查看检查ZK节点Standby一直处于standby但数据不同步JournalNode的edits目录损坏或磁盘满查看JournalNode日志检查journal目录磁盘空间客户端报NotActiveException客户端连接的NameNode不是当前Active检查客户端failover proxy provider配置格式化后两个NameNode无法组集群二次format导致namespaceID不一致确认日志中的namespaceID必要时清空数据重建JournalNode磁盘写满edits日志持续增长、没有定期清理监控磁盘扩展磁盘或迁移日志目录jar does not exist或is not a normal file配置的依赖路径错误或workers节点未分发jar包检查yarn.application.classpath和相关环境变量4.2 案例一NameNode宕机后自动切换失败这个案例值得单独展开因为它是最典型的“配置看着都对就是切换不了”的问题。有一次测试环境里我手动kill掉Active NameNode后等了很久Standby都没有接管。排查过程是这样的。先看Standby节点的ZKFC日志发现它一直在报“unable to get the lock”说明Standby侧的ZKFC根本没有抢到Zookeeper里的锁。然后我检查Zookeeper的节点状态发现锁节点依然存在。为什么Active进程都被kill了锁节点还在原因是ZKFC进程和NameNode是独立进程我只kill了NameNodeZKFC还活着它持有的临时锁节点就没有被释放Standby自然抢不到。这个案例说明一个关键点HA的故障切换针对的是“整个节点的故障”而不是“单个进程的故障”。如果NameNode进程挂了但ZKFC进程还活着ZKFC会检测到NameNode不健康然后主动释放锁并触发切换。但如果ZKFC自己也没了Zookeeper需要等待临时节点超时才能释放锁这个超时时间默认是10秒左右期间集群处于不可用状态。所以每次演练时最贴近真实故障的做法是直接断掉整台机器的电源或者执行kill -9杀掉这台机器上的所有相关进程而不是只杀NameNode。4.3 案例二日志报“jar does not exist or is not a normal file”这个报错看起来很低级但在实际运维里经常出现特别是在用脚本批量部署或者升级Hadoop版本之后。具体情况是你提交一个MapReduce作业YARN在启动容器的时候去加载某个jar包报错说路径不对。根本原因一般有三类。第一类是Hadoop自身的依赖路径变了比如你升级了Hadoop版本但yarn.application.classpath还写的是旧路径。检查yarn-site.xml里是否配置了classpath或者是否依赖yarn-env.sh里自动生成的路径确保新版本的所有jar目录都被正确包含。第二类是自定义的依赖jar包没有分发到所有NodeManager节点上只在提交作业的那台机器上存在。这种情况在测试环境很常见本地跑没问题提交到集群就报jar不存在本质上就是jar包没有通过-libjars参数或者分布式缓存分发到各个节点。第三类是配置的路径本身拼错了少了一层目录或者文件名大小写不对这种问题用ls命令验证一下就行了。排查这个报错的思路是不要只看报错那台机器的路径要全局检查所有NodeManager节点上该路径是否存在。因为YARN的容器可能在任意一个NodeManager上启动jar包只要缺一个节点作业就会随机失败。4.4 案例三扩容后数据不均衡扩容之后新DataNode磁盘是空的但写入的数据仍然集中在旧节点上这算正常现象。HDFS默认不会因为新节点加入就自动重新分布数据必须手动执行balancer。这里有一个容易漏掉的细节balancer在移动副本时会优先考虑“跨机架”的移动如果你的机架感知配置错误balancer可能反复移动数据但始终达不到均衡状态日志里会出现大量的Data is not being moved之类的警告。遇到这种情况优先检查拓扑脚本的输出是否符合预期。另外如果集群长期不写数据只是存储静态文件balancer移动完一轮后再也不会触发新增节点依然会被闲置。针对这种情况可以配置dfs.datanode.balance.bandwidthPerSec来控制均衡速度或者干脆把静态数据重新写一遍强制触发副本重新分布。不过手工重写数据有风险操作前务必确认业务可以接受短暂的写入中断。4.5 日常巡检与监控建议HA架构运行是否正常不能等故障了才知道。我梳理了一个简单的巡检清单每周做一遍能提前发现大部分隐患。检查所有NameNode和RM的状态确认主备角色符合预期不能出现双Active或者双Standby的情况。用hdfs haadmin -getAllServiceState和yarn rmadmin -getServiceState就能看到。检查JournalNode的磁盘空间edits日志是持续增长的磁盘满会导致NameNode无法提交元数据操作这是高危故障必须提前设置磁盘使用率告警。检查Zookeeper集群状态用zkServer.sh status确认leader存在、各节点都在正常参与选举。日常监控上重点盯NameNode的JVM堆内存使用、GC时间、JournalNode的同步延迟transactions、以及自动切换是否被意外触发过。踩过很多次坑之后我最大的体会是HA切换链路里的每个环节都可以单独做测试ZKFC的健康检查、Zookeeper的锁竞争、JournalNode的日志同步、Fencing脚本的执行任何一个环节出问题整个自动切换都会失效。所以新集群上线前无论如何都要做至少两次完整的故障演练一次模拟单节点宕机一次模拟网络分区确认系统的表现符合预期再交付给业务方使用。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻