ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hadoop高可用架构实战:NameNode与ResourceManager双活方案全解析

Hadoop高可用架构实战:NameNode与ResourceManager双活方案全解析 做大数据平台这些年我最怕的不是集群性能不够而是凌晨两点被电话叫醒说数据写不进去了。有一次排查了半天才发现NameNode 进程明明还活着可整个 HDFS 客户端已经全部超时所有 Flume 采集任务堆成山数据链路全断。那会儿集群还是单 NameNode 架构重启又不敢随便重启怕元数据丢了更麻烦只能硬着头皮一遍遍看日志。就是从那次之后我下定决心把 Hadoop 高可用方案彻底重构了一遍从 NameNode 到 ResourceManager 全部做了 HA。这篇就把我这套方案的设计思路、配置过程和踩坑记录完整梳理出来给正在规划集群容灾的同学一个可直接参考的落地样板。这套方案适合谁如果你的集群规模已经到了生产级别每天跑着实时采集、离线调度、即席查询数据链路不允许出现长时间中断那么 NameNode 单点和 ResourceManager 单点都是必须解决的问题。如果你是刚搭好 Hadoop 集群、准备上线的阶段提前把 HA 架构融进去也比后面再迁移省事得多。文章包括整体设计思路、核心组件原理、配置与部署细节、故障切换机制以及我实际运维中遇到的典型问题和排查方法看完可以直接对着操作。1. 高可用要解决的首先是单点故障这个老问题1.1 为什么说 NameNode 是集群最容易出事的节点Hadoop 1.x 时代的老架构里NameNode 就是绝对的枢纽。整个集群的命名空间、文件目录树、数据块到 DataNode 的映射关系全部存在 NameNode 内存里。客户端读写数据的第一步都是先跟 NameNode 要元数据拿到文件块的位置信息再去找 DataNode。这意味着 NameNode 一旦挂了客户端连文件在哪儿都不知道整个集群数据读写全部瘫痪。更要命的是早期 NameNode 没有热备机制。挂掉之后只能找一台新机器把元数据镜像和编辑日志恢复过去再重新启动。这个恢复过程短则几十分钟长则几个小时取决于元数据量的大小。想象一下线上业务正在跑突然几小时写不了数据Kafka 里的消息还在不断积压这损失不是一般的大。还有一个容易被忽略的点NameNode 进程存活并不代表服务可用。我遇到那次故障就属于这种情况进程在但 JVM 因为频繁 Full GC 导致 RPC 请求长时间无响应客户端那边表现为连接超时或读写卡死。这种“半死不活”的状态比直接宕机更隐蔽也更考验高可用方案的响应能力。1.2 高可用方案到底要解决哪几类问题设计一个完整的高可用方案至少需要覆盖四个层面第一是元数据高可用。NameNode 不能只有一个必须有一主一备或者多节点互备Active 节点挂掉时 Standby 节点能无缝接管命名空间服务。这是整个 HA 架构的核心。第二是数据高可用。数据块在多个 DataNode 上有副本这是 HDFS 默认就有的能力。但 HA 架构下还要考虑元数据存储本身的高可用也就是 edit log 不能被单点保存否则 NameNode 切换后丢失最近的写入记录。第三是计算层高可用。HDFS 解决的是存储YARN 的 ResourceManager 负责整个集群的资源调度同样是单点。RM 挂掉之后已经提交的作业不会立即消失但新的作业无法申请资源整个计算引擎等于停摆。所以 RM 也需要做主备切换。第四是自动故障转移。光有备节点不够还得能自动检测主节点故障、自动完成切换不然人工介入一样会有不小的时间窗口。自动切换一般需要依赖 ZooKeeper 做分布式协调这也解释了为什么 Hadoop HA 和 ZooKeeper 总是绑定出现。这四个层面不是相互独立的。元数据高可用是基础数据可靠性是保障计算层高可用是对上层业务的延伸而自动故障转移把所有环节串联起来。后面的整个设计都是在围绕这四个层面做落地方案。2. 方案选型与整体架构设计思路2.1 两种常见 HA 架构的对比与选择Hadoop NameNode HA 的主流实现有两种一种是基于 Quorum Journal ManagerQJM的方案另一种是基于共享存储的方案比如 NFS。共享存储的思路很简单让两个 NameNode 挂载同一个共享目录edit log 写到共享存储里Active 写Standby 从共享存储里读取并回放。表面上看配置也简单但实际生产环境里坑不少。NFS 本身就是单点虽然可以用商业存储设备扛但成本和运维复杂度直接上去了而且 NFS 挂载不稳定的时候两个 NameNode 之间的状态同步很容易出问题。QJM 方案就不存在这个隐患。它的设计思路是让 edit log 同时写到一组 JournalNode 节点上JournalNode 通常部署三台或五台组成一个小集群。Active NameNode 把每次元数据变更操作作为日志写入 JournalNode 集群Standby NameNode 从 JournalNode 读取这些日志并实时回放到自己的内存中。这样一来Active 和 Standby 的元数据状态始终保持同步而且不依赖任何外部共享存储设备。实际选型时我直接选择了 QJM。原因有三一是它完全消除了共享存储这个单点JournalNode 集群本身就是高可用的二是它不依赖特定硬件或商业存储普通服务器就能搞定三是它是 Hadoop 社区主推的方案后续升级、运维、问题排查都有成熟经验可循。如果你是在云上搭建集群选择 QJM 同样适用不绑定任何云厂商的专属存储。2.2 自动故障转移的设计ZooKeeper 和 ZKFC 的角色自动故障转移是整套 HA 方案里最见功力的一环。它是怎么实现的核心是两个组件ZooKeeper 集群和 ZooKeeper Failover ControllerZKFC。先说 ZooKeeper。它在这里主要承担三件事维护 NameNode 的活跃状态、提供分布式锁机制防止双主、保存 HA 状态信息。每个 NameNode 启动时都会尝试在 ZooKeeper 里创建一个临时节点比如 /hadoop-ha/mycluster/ActiveBreadCrumb。谁创建成功了谁就是 Active 节点。Active 节点挂了以后临时节点会自动消失Standby 节点通过 Watch 机制立刻感知到这个变化然后竞争创建节点完成切换。ZKFC 是运行在 NameNode 节点上的一个独立进程负责监控 NameNode 的健康状态并和 ZooKeeper 交互。每个 NameNode 对应一个 ZKFC 进程。它的工作流程大致是定时向本机 NameNode 发送健康检查命令如果 NameNode 正常就维持当前状态如果 NameNode 出了问题它就会尝试去 ZooKeeper 抢占 Active 节点同时触发隔离操作确保不会有多个节点同时进入 Active 状态。这里面最关键的设计就是“脑裂”防护。如果没有防护机制可能出现的情况是老 Active 节点没有完全宕机只是网络分区导致 ZooKeeper 联系不上它于是 ZKFC 把 Standby 切成了 Active。此时两个节点都认为自己是 Active都会尝试写 edit log元数据就乱了。所以切换之前旧节点必须被“隔离”也就是 fencing。常用的隔离方式是 sshfence通过 SSH 登录到旧 Active 节点杀掉对应的 NameNode 进程。这套机制保证了任何时刻集群里只有一个 Active NameNode。2.3 高可用架构对上层组件的影响范围把 HDFS 和 YARN 都做成 HA 之后对上层组件的影响是全面的。Hive、Spark、Flink、HBase 这些组件读写 HDFS 时通过 failover proxy provider 自动感知 NameNode 切换不需要改业务代码。YARN 的 RM 做了 HA 之后MapReduce 作业、Spark 作业提交时只需要配置好 RM 地址列表客户端会自动找到当前 Active 的 RM。不过要注意高可用不等于应用无感知。NameNode 切换的瞬间正在执行的写操作可能会收到重试异常所以客户端层面的重试机制一定要配好。dfs.client.failover.max.attempts 这个参数决定了客户端最大重试次数我一般会把它调大一些配合 exponential backoff 的机制切换期间短暂报错后会自动恢复业务侧基本无感。另外Hive 的 Metastore、HBase 的 HMaster 这些组件自身也有 HA 机制和 Hadoop 底层的 HA 是两回事但在整体方案设计里要一起考虑。我通常会把所有依赖 ZooKeeper 的组件统一规划到同一个 ZK 集群或者按职责拆成两套避免一个 ZK 集群出问题影响所有上层服务。3. 核心组件配置与实现要点3.1 JournalNode 集群的设计与部署要求JournalNode 承担着 edit log 的存储职责它的可靠性直接决定了 HA 能否正常工作。部署上有几个硬性要求必须注意。首先是数量。QJM 基于多数派写入协议也就是说每次写入必须得到超过半数的 JournalNode 确认才算写入成功。如果配置了 3 台 JournalNode最多只能容忍 1 台故障配置 5 台最多容忍 2 台故障。所以数量一般取奇数避免出现“平局”的情况。生产环境我建议至少 3 台数据量极大、集群规模较大的场景考虑 5 台再往上收益就不明显了。JournalNode 可以独立部署也可以和 ZooKeeper 混部在同一批节点上。我在方案里就是把 JournalNode 和 ZooKeeper 放在同一组机器上三台机器既跑 JournalNode 又跑 ZooKeeper。这样做的原因是这两个组件都是轻量级进程对 CPU 和内存消耗不大混部可以节省服务器成本。不过磁盘 IO 要注意JournalNode 的写入比较频繁最好单独挂一块独立的数据盘不要和系统盘或者其它大数据组件的数据目录混在一起。JournalNode 的存储目录通过 dfs.journalnode.edits.dir 配置。这个目录存放的是 edit log 文件必须保证有足够的磁盘空间。我一般会根据集群的元数据更新频率来估算同时配置监控告警。曾经遇到过 JournalNode 磁盘写满导致 edit log 写入失败Active NameNode 直接退出服务的严重事故这个坑后面细说。3.2 关键配置参数逐项解析我直接把一套可用的核心配置贴出来然后逐个讲清楚每个参数的作用和调整思路。下面的配置基于 Hadoop 3.x 版本。core-site.xml 中最核心的是 fs.defaultFS 和 ZooKeeper 连接地址。configuration property namefs.defaultFS/name valuehdfs://mycluster/value /property property nameha.zookeeper.quorum/name valuenode1:2181,node2:2181,node3:2181/value /property /configurationfs.defaultFS 的值不再是某个具体节点的地址而是一个逻辑名称服务 mycluster。客户端通过这个名称服务找到当前 Active 的 NameNode而不需要关心具体是哪台机器。ha.zookeeper.quorum 是 ZK 集群的地址列表ZKFC 和 YARN 都会用到。hdfs-site.xml 中的配置量最大。我把它们分成几个组来讲。名称服务与 NameNode 标识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 valuenode1:8020/value /property property namedfs.namenode.rpc-address.mycluster.nn2/name valuenode2:8020/value /property property namedfs.namenode.http-address.mycluster.nn1/name valuenode1:9870/value /property property namedfs.namenode.http-address.mycluster.nn2/name valuenode2:9870/value /propertydfs.nameservices 定义逻辑名称dfs.ha.namenodes.mycluster 定义这个名称服务下有哪些 NameNode。每个 NameNode 都有独立的 RPC 地址和 HTTP UI 地址这里的 node1、node2 要替换成你集群实际的机器名或 IP。注意 Hadoop 3.x 里 NameNode UI 的默认端口是 9870不是 2.x 时代的 50070。JournalNode 相关配置property namedfs.namenode.shared.edits.dir/name valueqjournal://node1:8485;node2:8485;node3:8485/mycluster/value /property property namedfs.journalnode.edits.dir/name value/data/hadoop/journal/value /propertydfs.namenode.shared.edits.dir 声明了 edit log 写到哪个 JournalNode 集群语义是 qjournal://journalnode1:8485;journalnode2:8485;journalnode3:8485/名称服务ID。JournalNode 默认通信端口是 8485。dfs.journalnode.edits.dir 是每个 JournalNode 节点上实际保存 edit log 文件的本地路径。故障转移与隔离配置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 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 /propertydfs.ha.automatic-failover.enabled 置为 true表示开启自动故障转移。dfs.client.failover.proxy.provider.mycluster 指定 Hadoop 客户端使用的故障转移代理类这个类会尝试连接当前 Active NameNode失败后自动切换到另一个。fencing 相关配置决定了旧 Active 如何被隔离sshfence 通过 SSH 执行 fuser 或 kill 命令杀掉旧主节点的 NameNode 进程。一定要保证节点之间 SSH 免密登录配好私钥路径也要对否则切换时隔离操作会失败。3.3 ResourceManager HA 的关键配置HDFS 的 HA 搞定了YARN 层面同样不能放松。ResourceManager 的 HA 配置相对简单核心是把 RM 的状态存储放到 ZooKeeper 上这样 Active RM 挂了以后Standby RM 可以从 ZK 里恢复调度器状态和运行中作业的元信息。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 property nameyarn.resourcemanager.hostname.rm1/name valuenode1/value /property property nameyarn.resourcemanager.hostname.rm2/name valuenode2/value /property property nameyarn.resourcemanager.zk-address/name valuenode1:2181,node2:2181,node3: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这几个参数的逻辑和 HDFS 的 HA 很像。yarn.resourcemanager.ha.enabled 开启 HAyarn.resourcemanager.cluster-id 是逻辑集群 IDyarn.resourcemanager.ha.rm-ids 列出所有 RM 的标识hostname 对应的就是每一台 RM 的实际地址。最关键的是 yarn.resourcemanager.store.class 指定为 ZKRMStateStore这样一来调度器状态、已提交的应用列表、Token 等信息都持久化到 ZooKeeper。切换后新 Active RM 从 ZK 恢复这些状态用户提交的作业不会丢。4. 实操部署过程与关键命令4.1 部署前的环境准备和检查清单在动手配置之前有几项基础检查如果没做后面一定会出问题。第一个是节点间免密登录。HA 切换时要通过 SSH 去执行 fencing 操作所以所有 NameNode 节点之间必须配置免密。如果 journalnode 和 NameNode 不是同一批机器也要把所有相关节点的互信配好。我建议在安装阶段就把整个集群的 SSH 互信统一配好不要只配主节点之间的避免后期加节点时遗漏。第二个是 ZooKeeper 集群必须提前部署好。HDFS 的 ZKFC 和 YARN 的 RM 状态存储都依赖 ZK所以 ZK 集群的稳定性是 HA 方案的地基。ZooKeeper 集群至少 3 台奇数台这个没得商量。第三个是机器时间要同步。HA 切换过程中涉及大量分布式协调逻辑虽然 QJM 对时钟同步的要求没有某些数据库那么严格但节点间时间偏差过大会导致日志时间戳混乱排查问题的时候会非常痛苦。装个 chrony 或者 ntpd把全集群的时间同步到同一台时间服务器这个步骤不要省。第四个是磁盘空间评估。JournalNode 的数据目录、NameNode 的元数据目录都要单独评估容量。JournalNode 的 edit log 会持续增长虽然有 segment 滚动机制但不会自动清理。NameNode 的 fsimage 和 edits 也需要保留足够空间。我在生产环境里遇到过因为磁盘满导致整个 HA 状态被破坏的严重故障后面问题排查部分会详细说。4.2 完整配置与初始化步骤下面是我在一套三节点集群上实际执行过的完整步骤节点规划如下node1 和 node2 部署 NameNode、ResourceManager、ZKFC、ZooKeeper、JournalNodenode3 部署 ZooKeeper、JournalNode、DataNode、NodeManager。DataNode 和 NodeManager 在三台机器上都部署为了排版简洁这里不展开全部 server 配置文件。所有节点的 /etc/hosts 都配上主机名映射192.168.100.11 node1 192.168.100.12 node2 192.168.100.13 node3第一步在所有节点上准备好 Hadoop 安装包和环境变量确保 hadoop 命令可用。然后在 node1、node2、node3 上分别启动 JournalNode。注意顺序很重要JournalNode 必须先启动因为后续格式化和启动 NameNode 时都需要往 JournalNode 上写 edit log。hdfs --daemon start journalnode启动后确认端口 8485 处于监听状态。可以用 ss -lntp 查看或者看日志里有没有报错。第二步在 node1 上执行 NameNode 的格式化操作。这一步只在第一次部署时执行。hdfs namenode -format格式化会在本地生成 NameNode 的元数据目录包括当前 fsimage。格式化命令执行完成后node1 的元数据目录里会有一份初始的命名空间状态。第三步启动 node1 的 NameNode 作为初始 Active 节点。hdfs --daemon start namenode这时启动的是普通模式还没有进入 HA 状态只是为了生成元数据供 node2 同步使用。第四步在 node2 上执行 bootstrapStandby把 node1 的元数据同步到本地。hdfs namenode -bootstrapStandby这个命令会从 Active NameNode 拉取当前的 fsimage 和 edit log构建一份 Standby 节点需要的元数据副本。如果没有执行这一步node2 启动时会因为缺少元数据而无法成为 Standby。第五步初始化 ZKFC 在 ZooKeeper 中保存 HA 状态所需的节点。在 node1 上执行一次即可。hdfs zkfc -formatZK这条命令会在 ZooKeeper 中创建 /hadoop-ha/mycluster 路径以及相关节点。如果之前初始化过再次执行会报错需要根据提示确认清理。第六步在 node1 和 node2 上分别启动 ZKFC 进程。hdfs --daemon start zkfcZKFC 启动后会向 ZooKeeper 注册竞争 Active 状态。此时可以看到某一个节点的 NameNode 状态变为 Active另一个变为 Standby。可以通过 NameNode 的 Web 页面看到状态也可以在命令行查看。第七步执行 start-dfs.sh 启动整个 HDFS 相关进程。实际上这一步会把已经手动启动的 NameNode、JournalNode、ZKFC 一起管理起来同时启动所有 DataNode。但是我前面几步手动启动是为了保证顺序可控避免一上来就是全套启动可能导致的顺序错乱。start-dfs.sh第八步启动 YARN 集群。start-yarn.shResourceManager 的 HA 配置好之后start-yarn.sh 会分别启动两个 RM 进程它们通过 ZooKeeper 实现自动选主。可以从 yarn.resourcemanager.webapp.address 对应的 Web 页面看到当前哪个 RM 是 Active。4.3 如何验证高可用是否真正生效部署完成不代表高可用就生效了必须做一次完整的故障演练。我每次上线 HA 方案后都会在业务低峰期做一次主动切换测试。测试方法很简单登录当前 Active NameNode 所在的节点直接 kill 掉 NameNode 进程。kill -9 namenode_pid正常情况下几秒钟后另一个节点上的 NameNode 会从 Standby 变成 Active。观察以下几个指标第一ZKFC 的日志里会出现状态切换记录。在 node2 的日志目录下查看 hadoop-hadoop-zkfc-node2.log能看到类似 Transitioned to active 的记录。第二客户端读写是否能在重试后恢复。可以写一个小脚本循环往 HDFS 上创建文件观察切换过程中是否有失败以及失败后是否自动恢复。我一般会开一个终端持续执行 hdfs dfs -put 操作切换完成后确认脚本能继续跑通。第三检查新 Active NameNode 的元数据是否完整。在切换完成之后立刻执行 hdfs fsck / 做一次文件系统检查确认没有块丢失或者元数据损坏。ResourceManager 的测试思路类似杀掉 Active RM 进程然后观察另一个 RM 是否接管提交一个测试作业确认资源调度正常。建议把这一整套测试流程做成文档每次集群升级或者配置变更之后都跑一遍不要等出了故障才发现 HA 是摆设。5. 常见问题与排查技巧实录5.1 JournalNode 磁盘写满导致 Active 退出这个是我遇到过的故障中最棘手的一个。某个时间段内集群的元数据写入量激增而 JournalNode 的数据盘容量本来就偏小结果磁盘被 edit log 写满了。Active NameNode 尝试往 JournalNode 写日志时JournalNode 返回写入失败。QJM 机制要求多数派 JournalNode 确认写入如果写入失败Active NameNode 会认为自己无法正常持久化元数据于是主动退出 Active 状态甚至直接进程退出。这是 QJM 设计上的安全机制宁可停止服务也不能在元数据不能持久化的情况下继续对外服务。但问题在于如果只挂了一台 JournalNode 的磁盘另外两台正常多数派还是能成立的Active 不应该退出。我遇到的情况是那台磁盘满的 JournalNode 开始疯狂报错同时它所在的机器 IO 异常拖慢了 ZK 的通信导致 ZKFC 误判 NameNode 状态触发了切换。排查这类问题第一件事就是看 JournalNode 日志确认是不是磁盘满了。第二件事是看 ZKFC 日志确认切换是因为 NameNode 心跳超时触发还是因为元数据写入失败触发。定位到具体原因后清理磁盘、扩容磁盘、重启 JournalNode让它重新同步 edit log。但更关键的是预防。我在所有 JournalNode 上加了磁盘使用率监控阈值定在 80% 就告警。同时把 edit log 的保留策略和 fsimage checkpoint 频率调了一下让旧的 edit log 能定期被合并清理避免无限增长。Hadoop 3.x 里的 dfs.namenode.edit.log.roll.num.segments 和 dfs.namenode.checkpoint.period 这些参数可以配合调整具体值要根据集群的元数据写入量来定。5.2 ZKFC 无法完成自动切换的排查另一个高频问题是Active NameNode 已经挂了但 Standby 节点迟迟不切换。这种时候集群处于“无主”状态读写全部失败比单 NameNode 故障还难受。我遇到过几次原因各不相同这里列几个典型的一种是 ZooKeeper 的连接问题。ZKFC 和 ZooKeeper 之间的 session 超时时间设置不合理导致 ZKFC 不能及时感知 Active 节点消失或者 ZooKeeper 集群本身负载过高处理心跳变慢。这种情况下先检查 ZK 集群的健康状态再适当调整 session 超时时间。另一种是 fencing 失败导致切换中止。当 Standby 节点尝试切换为 Active 之前会先对旧 Active 执行隔离。如果 SSH 免密失效、私钥路径不对、或者目标节点网络不通fencing 操作会一直重试到超时切换永远不会完成。我遇到过最坑的情况是旧节点上 NameNode 进程变成了僵尸状态kill 命令杀不掉fencing 一直卡住。后面我改用 shellfence 方式在隔离脚本里加了一层杀进程的兜底逻辑才彻底解决了这个问题。还有一种情况是 ZKFC 进程本身挂了。ZKFC 不像 NameNode 那样有守护机制它挂了之后节点就失去了自动故障转移的能力。建议在节点上配置好进程守护用 systemd 或 supervisor 管理 ZKFC确保它挂了能自动拉起。5.3 切换后出现双 Active 或脑裂怎么办双 Active 是 HA 架构里最危险的异常状态意味着两个 NameNode 同时认为自己是主节点都在往 JournalNode 写 edit log元数据很快会不一致甚至损坏。正常情况下 fencing 机制会阻止这种情况但一切机制都有失效的可能。比如网络分区时旧 Active 无法连接 ZooKeeper而 ZK 又无法通过 fencing 杀死旧 Active此时新 Active 可能在隔离未完成的情况下顶上来。这种局面下唯一正确的操作就是人工介入。我的处理步骤是先停掉所有客户端写入然后马上确认两个节点的状态登录两个节点分别执行 hdfs haadmin -getAllServiceState 查看。接着把非预期的那台 Active 手动转为 Standby 或直接停掉进程等网络恢复后确认整个集群元数据一致性没有问题再恢复写入。如果元数据已经不一致可能需要从 fsimage 和 edit log 做恢复这种场景非常麻烦所以平时一定要做好 NameNode 元数据目录的定期备份。预防脑裂的关键在于 fencing 配置。我强烈建议生产环境把 fencing 方法配成 sshfence 加 shellfence 的组合或者至少在 sshfence 之外加一道保险确保旧 Active 无法继续对外提供服务。另外 ZooKeeper 集群本身要稳定网络分区问题不是我们能完全控制的但 ZK 节点多、分布合理可以降低分区带来的风险。5.4 常见问题速查表现象可能原因排查思路与解决方法NameNode 无法启动元数据目录没有初始化或损坏检查 dfs.namenode.name.dir 目录内容必要时使用 fsimage 备份恢复Standby 元数据一直跟不上 ActiveJournalNode 性能瓶颈或网络分区查看 JournalNode 日志和网络延迟检查 JournalNode 磁盘 IO切换后客户端长时间不可用客户端重试配置不足调大 dfs.client.failover.max.attempts开启重试退避机制ZKFC 报 ConnectionLossZooKeeper 节点负载过高或不可达检查 ZK 集群状态查看 ZK 日志优化 ZK 配置或扩容ResourceManager 切换后作业状态丢失未启用 ZKRMStateStore确认 yarn.resourcemanager.store.class 配置并重启 RMJournalNode 同步异常节点磁盘满或日志损坏清理磁盘必要时删除本地 edits 目录并重启 JournalNode 重新同步这张表是我平时排查问题的起点碰到问题先对照一遍很多表面现象背后的根因都是相似的。6. 运维经验和高可用方案的扩展思考6.1 日志和监控是 HA 的生命线HA 方案做完了最怕的其实是“看起来一切正常出了事才发现监控没覆盖”。我上过不少当之后总结了一条经验高可用域内的所有关键组件都要有独立监控而不是只监控整个集群的总体状态。JournalNode 和 ZKFC 这两个角色最容易被忽视。普通监控一般只关注 NameNode 是否存活很少有人逐个检查 JournalNode 的磁盘空间和 ZKFC 进程状态。可恰恰是它们的问题会在一段时间后酿成大的故障。我在公司内部的监控平台上把这三样指标都加了告警JournalNode 的磁盘使用率、ZKFC 进程是否存在、ZooKeeper 的会话数是否异常下降。另外NameNode 切换事件一定要能即时感知。每次切换都会在 ZKFC 日志里留下记录我用脚本定时扫描日志中的切换关键字一旦发现 Transition to active 这类信息就触发告警。因为正常情况下集群不应该频繁切换如果一段时间内出现多次切换说明某个节点可能状态不稳定需要提前排查。6.2 元数据备份永远不能省不管 HA 做得多么完善元数据备份都是最后一道安全网。HA 保证的是节点故障场景下的可用性但如果整个元数据目录因为人为误删、磁盘损坏、软件 bug 等原因出现不可逆的损失HA 也无法帮你恢复。我采取的方案是每天都把 Active NameNode 的 fsimage 文件拷贝到独立的备份节点或对象存储上保留最近 30 天的版本。同时把 NameNode 元数据目录用单独的磁盘挂载降低系统盘故障带来的风险。虽然这些操作不复杂但关键时刻能救命。6.3 关于集群规模与 HA 成本的权衡最后想聊聊 HA 方案的适用边界。并不是所有 Hadoop 集群都需要做一整套 HA。如果你的集群只有三四台节点、跑的是开发测试环境、或者业务允许长时间中断那么过度设计只会增加维护成本。JournalNode 至少三台、ZooKeeper 至少三台再加上双 NameNode、双 ResourceManager硬件成本直接多出不少。但如果集群已经承载核心业务比如实时数仓、推荐系统、用户行为分析这类链路宕机一小时就是真金白银的损失那么 HA 不是可选项而是必选项。我的建议是在集群从测试走向生产的同时就把 HA 架构一并规划进去不要等到业务跑起来之后再重构那样迁移成本和风险都高得多。从我自己操作的经验来看QJM ZooKeeper 自动故障转移这套组合在 Hadoop 生态里已经非常成熟只要把基础配置做扎实、把故障演练变成常态、把监控覆盖到关键组件它就真的能让你在生产环境里睡个安稳觉。最朴素的道理反而是最值得记住的高可用方案不是买保险是需要长期维护和验证的工程系统每一次真实的切换演练都比嘴上说“我们做了 HA”更有价值。
返回列表