1. 现象描述这不是界面抽风是注册链路断了有不少刚搭好 Hadoop 集群的朋友都会遇到这么一幕打开 NameNode 的 Web 管理界面新版本默认是http://namenode主机名:9870/dfshealth.html#tab-overview老版本是 50070 端口切到 Datanodes 标签页里面孤零零躺着一个节点其余几台机器怎么都刷不出来。你刷新页面、重启服务、重启电脑结果还是一样。这时候最需要先冷静下来搞清楚一件事Web 界面上的 Datanode 列表本质上是 NameNode 内存里“已注册 DataNode 集合”的投影。界面只是如实反映了 NameNode 当前收到了多少条心跳和一个块报告。换句话说列表里没有某个节点真正含义是“NameNode 根本没有收到该 DataNode 的注册请求或心跳”而不是界面坏了。理解到这一层排查思路就清晰了。DataNode 要出现在 Web 界面上至少要走过这么一条完整的链路DataNode 进程启动 → 读取本地数据目录里的current/VERSION文件拿到集群ID → 向 NameNode 的 8020或 9000/9820取决于core-site.xml里的配置端口发起注册请求 → NameNode 校验集群ID、命名空间ID、软件版本是否匹配 → 校验通过后把该节点加入在线列表 → DataNode 每隔 3 秒发一次心跳、每 6 小时发一次完整块报告。这条链路中任何一个环节断掉表现出来就是你看到的“只有一个 datanode”或者“一个 datanode 都不显示”。需要特别提醒的是如果界面上连一个节点都没有多半是 NameNode 和 DataNode 之间完全不通或者 DataNode 压根没启动成功如果其中有且只有一个节点那你就要重点怀疑“为什么偏偏只有这一台能注册上”。这个问题的答案往往藏在主机名解析、集群ID和配置文件差异里。按照我这些年帮人排查的经验十个类似案例里大概有六个是集群ID不一致、两个是主机名解析问题、一个半是防火墙或端口不通剩下的才是各种稀奇古怪的原因。下面我逐步拆解按“先看现象 → 再查日志 → 最后动手修”的顺序来说保证你拿着这篇文章就能一步步把问题按死。2. 先搞懂 DataNode 注册机制再谈排查2.1 一次完整的注册过程到底发生了什么DataNode 启动后做的第一件正经事就是尝试和 NameNode 建立连接。它读的是hdfs-site.xml里的dfs.datanode.data.dir指定的目录每个目录下都有一个current文件夹里面放着VERSION文件。这个文件里记录着clusterID、namespaceID、storageID、cTime等信息。DataNode 打开这个文件把里面的集群ID、命名空间ID打包进注册请求发给 NameNode。NameNode 那边收到请求后会做三件事第一检查发来请求的 IP 是否在dfs.hosts/dfs.hosts.exclude许可名单范围内如果配置了的话第二比对集群ID、命名空间ID是否和自身dfs.namenode.name.dir里记录的一致第三比对软件版本Hadoop 大版本不同会导致协议不兼容。三步全过才把 DataNode 的信息写进自己的内存列表同时返回一个注册成功的响应。之后 DataNode 才算“入伙”开始按 3 秒间隔发心跳。这里有一个特别容易让人迷惑的点DataNode 是否注册成功和它能不能跟 NameNode 通信是两回事。TCP 能通不意味着注册能成功因为还有集群ID和数据格式的校验。很多人在排查时只测了端口通不通发现能通就以为万事大吉结果卡在集群ID上一直没发现。我后面会专门讲这个坑。2.2 图形界面上的“DataNode 列表”为什么可信但有限NameNode 的 Web UI 上Datanodes 标签页展示的表格由/dfshealth.html页面后端动态生成数据源是 NameNode 内存里的DatanodeDescriptor集合。Web 监听线程从这块内存里读出在线节点信息再渲染成 HTML。这个列表是准实时快照并不是每秒钟都在变通常会有几秒到十几秒的延迟但整体可信。它只包括已注册的 DataNode不包括正在启动中还没完成注册的节点也不包括已停止心跳但还没超时的节点这类节点会先被标记为“Dead”过一段时间才从列表里消失。所以如果你在界面上看到某个机器没有出现在列表里你应该按照“进程序号 → 注册请求 → 心跳”的顺序去查而不是反复刷新页面。很多人一整天就在那点刷新按钮顺便重启一遍集群这是纯属折腾。下面这张表帮你快速根据界面现象判断问题大概率出在哪儿界面现象可能的根源优先检查方向列表里一个 DataNode 都没有DataNode 进程全局性没启动 或 所有 DataNode 都无法连上 NameNodejps看进程telnet 测 8020 端口列表中只有 1 个节点其他没有集群ID/namespaceID 不一致 或 主机名解析差异 或 防火墙阻止部分节点对比各节点VERSION文件ping 主机名节点曾经在列表里后来消失了节点宕机、进程被杀、磁盘故障、心跳超时查看 DataNode 日志检查磁盘空间节点显示为 Dead / stale心跳延迟超过dfs.namenode.heartbeat.recheck-interval网络延迟、负载过高、Java GC 停顿3. 完整排查流程与解决方法3.1 第一步用 jps 确认所有节点的进程状态排查的第一步永远是看进程而不是改配置。登录到那台“消失”的机器上执行jps或者更精确一点只看 Hadoop 相关进程jps -l | grep DataNode正常情况下你应该看到类似这样的输出12345 org.apache.hadoop.hdfs.server.datanode.DataNode如果输出里只有jps本身或者根本没有 DataNode 进程那就别往下查了问题就是 DataNode 没启动。最常见的原因有两个一是你只在 NameNode 机器上执行了start-dfs.sh而这台机器的配置里没被纳入 slaves/workers 文件二是 DataNode 启动后立刻崩了日志里能看得一清二楚。关于start-dfs.sh到底会启动哪些机器上的 DataNode这里多说一句。新的 Hadoop 版本里你需要在etc/hadoop/workers文件老版本叫slaves中一行一个主机名列出所有要跑 DataNode 的机器。如果你在配置集群时只把 NameNode 自己写进去了其他机器自然不会启动 DataNode。检查一下cat $HADOOP_HOME/etc/hadoop/workers如果这个文件里只有一行localhost或者只有 NameNode 的主机名那问题就在这儿。把其他节点的主机名逐行加进去注意不要有空行和多余的空白符否则脚本在解析时可能出错。改完之后在 NameNode 机器上重新执行start-dfs.sh即可。如果说jps能看到 DataNode 进程但是界面里还是没有它那就进入下一步去看日志。顺便提一句我用jps之前通常会先看下有没有设置HADOOP_HOME和PATH否则直接敲jps会提示命令找不到。如果遇到这种情况可以先手动指定$JAVA_HOME/bin/jps或者用ps -ef | grep DataNode代替。3.2 第二步从日志里找出真实的拒绝原因日志是一切排查的最终裁判。DataNode 的日志位置一般在$HADOOP_LOG_DIR下默认是$HADOOP_HOME/logs不配置的话会在当前用户的~/hadoop-用户名/目录下。文件名形如hadoop-用户名-datanode-主机名.log。用 tail 命令看最后 100 行tail -n 100 $HADOOP_HOME/logs/hadoop-$(whoami)-datanode-$(hostname).log常见的关键报错有这么几种我直接给你列出来并且翻译成人话如果看到类似Incompatible clusterIDs in ...或者Storage directory ... is not formatted for ...的报错那基本坐实了集群ID不一致的问题。这通常是因为你曾经多次执行hdfs namenode -format每次格式化都会生成一个新的 clusterID而 DataNode 的数据目录里还留存着旧格式化时写下的 clusterID。两边的 ID 对不上NameNode 自然拒绝注册。解决办法我放在第五步里详细说。如果看到Connection refused或者connect to ... 8020 failed说明 DataNode 进程虽然活着但它根本连不上 NameNode 的 RPC 端口。去 NameNode 机器上看 8020 端口有没有在监听netstat -tlnp | grep 8020如果端口没在监听去查 NameNode 进程是不是活着以及core-site.xml里fs.defaultFS配的端口和实际启动的是否一致。曾经有人把fs.defaultFS里的端口写成 9000实际启动时用默认配置跑在了 8020 上结果 DataNode 全部连不上页面只有一个节点都没有这类问题最气人。如果看到Permission denied或者datanode cannot access namenode之类的字样先检查是不是防火墙拦截了内网通信。但这个报错出现的概率没有前面几种高我把它放在第四步一起说。还有一个小细节DataNode 日志会持续滚动如果看不到明显的 ERROR可以搜索关键字FATAL和WARN有些致命错误恰恰藏在 FATAL 里。特别是FATAL: Storage directory ...这种直接告诉你哪个目录出事了。3.3 第三步核对主机名解析与 IP 映射这一类的典型案例特别有意思。界面上有一台 DataNode 正常显示其他几台死活不出现。你登录到那些“失踪”的机器上jps能看到 DataNode 进程日志里也没有报错甚至还能看到 DataNode 在努力连 NameNode。这时候你要关注的不是连接本身而是 DataNode 用什么主机名去连 NameNode以及 NameNode 能不能反向解析回去。Hadoop 的 DataNode 启动时会从core-site.xml的fs.defaultFS里读取 NameNode 的地址。如果配置里写的是 IPDataNode 就用 IP 连写的是主机名DataNode 就先通过本地/etc/hosts或 DNS 解析拿到 IP 再连。问题往往出在/etc/hosts上有些人在配置集群时把每台机器的主机名解析写错了比如把其它机器的 IP 写成了127.0.0.1或者干脆没写映射。结果 NameNode 收到注册请求后尝试记录 DataNode 的地址时解析不到对应的合法主机名就把这条注册请求当作非法请求丢弃了。排查方法很简单。先在 NameNode 机器上执行ping datanode-hostname再在 DataNode 机器上执行ping namenode-hostname两边能通是前提但光通还不够。因为 Hadoop 内部还涉及到主机名的双向解析NameNode 要知道 DataNode 的 hostname 是什么DataNode 也要知道自己该用什么 hostname 去和 NameNode 通信。有些集群里机器的是内网 IP/etc/hosts里没有写对应的主机名解析Hadoop 就会用 IP 当主机名虽然也能跑但某些版本里会出现界面显示不全或者节点莫名其妙掉线的情况。最稳妥的办法所有机器上的/etc/hosts里统一把每台机器的主机名和 IP 映射写好且保证各机器之间互相能 ping 通主机名。这里给一份参考写法192.168.10.11 namenode 192.168.10.12 datanode1 192.168.10.13 datanode2 192.168.10.14 datanode3注意行与行之间不要有空行干扰也不要有多余空格。/etc/hosts里的127.0.1.1那行注释掉或者改成真实内网 IP避免 Hadoop 进程优先绑到回环地址上导致其他节点连不上它。3.4 第四步检查防火墙与端口连通性防火墙是第二常见的原因但它的表现和集群ID不一致完全不同。DataNode 进程活着日志里也没有特别明显的报错就是注册不上。这时候你telnet一下 8020 端口telnet namenode-ip 8020如果卡住或者直接Connection closed by foreign host说明 NameNode 的 RPC 端口被防火墙挡了。去 NameNode 机器上看防火墙状态systemctl status firewalld如果是开启状态可以直接添加放行规则然后把 8020 端口或者你实际用的那个端口放行。这里有一个很多人踩过的坑只放行了 Web 端口 9870忘了放行 RPC 端口 8020。于是浏览器能打开管理界面看到列表里只有一个节点但 DataNode 实际上一个都连不进来。因为我前面说了Web UI 是从 NameNode 内存里读数据Web 端口通不代表数据节点注册端口通。放行方式按你的网络管理规范来这里给一个最直接的参考firewall-cmd --permanent --add-port8020/tcp firewall-cmd --permanent --add-port9870/tcp firewall-cmd --permanent --add-port9864/tcp firewall-cmd --reload9864是 DataNode 的数据传输端口集群里 DataNode 之间和客户端上传下载都用它。如果只放行了注册端口而没放行数据端口你可能会遇到一个更奇怪的现象节点能出现在界面上但是文件上传失败或者写入报错。这一步建议一次配齐。还有一种属于“软墙”的情况你用的是云服务器安全组规则里没放行对应端口。这个不属于系统防火墙但效果跟防火墙一模一样。如果是云环境记得去控制台的安全组里检查入站规则把 NameNode 的 RPC 端口和数据端口都放行。3.5 第五步清理集群ID不一致的问题这一步是整个排查流程里最核心、也是解决概率最高的一步。前面提到hdfs namenode -format执行太多次会让 NameNode 的current/VERSION文件里记录一个clusterID而各个 DataNode 数据目录里的VERSION文件记录的是上一次格式化之前的旧clusterID。两边对不上NameNode 直接拒绝日志里会明确告诉你incompatible clusterIDs。怎么确认分别 SSH 到 NameNode 和 DataNode 机器上打开 VERSION 文件cat $HADOOP_HOME/hadoop_data/hdfs/namenode/current/VERSION cat $HADOOP_HOME/hadoop_data/hdfs/datanode/current/VERSION把两个文件里的clusterID字段拿出来对比就知道了。如果你发现不一致最简单的解决办法不是手动改 VERSION 文件而是把 DataNode 的数据目录数据清掉让它下次启动时重新注册。手动改 VERSION 文件虽然可行但非常容易手滑改错别字段一旦把storageID改串了后面又是一堆幺蛾子。清理前先停掉 DataNode 进程hdfs --daemon stop datanode # 或者 $HADOOP_HOME/sbin/hadoop-daemon.sh stop datanode然后删除 DataNode 数据目录里的内容。注意我只建议删 DataNode 的不建议删 NameNode 的因为 NameNode 里的元数据是你所有的目录、文件、块映射信息删了等于删库。删除之后重新启动hdfs --daemon start datanodeDataNode 启动时会发现自己数据目录里没有VERSION文件它会以“新节点”的身份重新向 NameNode 注册NameNode 会分配当前集群的 clusterID 给它。这样一来注册就通过了。如果你有多个 DataNode 都出现这个问题要逐一登录到每台机器上执行清理操作。顺手把命令写成一个串行循环可以在多台机器上跑但我不建议你不理解原理就盲目批量清理还是逐台来一次更稳妥。这里需要强调一个非常容易搞混淆的概念清掉 DataNode 数据目录不会导致 HDFS 里的数据丢失。因为 DataNode 存储的是数据块的副本NameNode 知道每个块在哪台机器上有副本。如果一个节点带着旧集群ID回来了NameNode 在后续复制机制里还会重新给它分配块。只有当所有 DataNode 的数据目录都被清了而 NameNode 又不知道块在哪儿时数据才会“看起来丢了”。所以单独清理某个 DataNode 是安全的。3.6 第六步重启并验证所有修改做完之后以一个干净的状态重新拉起整个集群。在 NameNode 机器上执行$HADOOP_HOME/sbin/stop-dfs.sh $HADOOP_HOME/sbin/start-dfs.sh等一两分钟让各个进程充分启动和注册然后去 Web UI 刷新或者直接在命令行用权威命令验证hdfs dfsadmin -report这个命令会列出 NameNode 认识的所有 DataNode包括每个节点的状态、存储容量、块数量。如果这里能看到所有节点Web UI 里肯定也会显示。注意dfsadmin -report的输出是直接从 NameNode 内存里读的比 Web 页面更快更准确排查时建议优先看这个。如果重启后还是不行别灰心回到第二步重新看日志。很多人漏了一个关键操作修改配置或者清理数据之后没有重启相应进程。尤其是 DataNode 的修改如果你只执行了jps发现进程还在那它还在用旧配置和旧VERSION数据活着你改的文件它根本不知道。记住一条铁律一切 HDFS 配置文件改动和数据目录清理都要以进程重启为生效前提。4. 常见问题速查与避坑指南4.1 高频问题对照表我把自己和同事在实际运维中遇到过的高频问题整理成了表格对照着查比盲猜快得多症状日志关键特征直接原因处理方法所有 DataNode 都不在界面里Connection refused/connect failedNameNode 端口没监听或 DataNode 连不上检查 8020 端口监听状态、fs.defaultFS配置界面只有一台 DataNodeIncompatible clusterIDs集群ID不一致重置 DataNode 数据目录并重启DataNode 进程反复退出FATAL: Storage directory...数据目录权限不对或无写入权限确认目录属主chown -R给对应用户节点出现在列表但很快变 Dead心跳超时日志无异常网络抖动或负载过高导致心跳延迟检查网络延迟调大心跳超时参数只有一个节点能注册日志中无报错但注册失败/etc/hosts解析异常统一 hosts 映射双端 ping 通主机名Web 能打开列表为空RPC 端口被防火墙拦截只放行 Web 端口没放行 8020放行 8020/9864 端口云环境检查安全组4.2 关于集群ID的独家经验集群ID这个问题看起来简单实际上有好几个变体。除了 NameNode 和 DataNode 不一致之外还有两种场面你可能也会遇到。第一种场面DataNode 节点之间集群ID不一致。如果你之前用旧版本的部署脚本初始化过集群后来又重新搭了一套导致部分 DataNode 数据目录残留旧集群ID。这种问题不会让所有节点都消失而是让一部分节点注册失败。同一个集群里ID 不一致的 DataNode 会彼此独立的跟 NameNode 沟通但都会被拒。现象就是界面上只显示一两个节点其他全部消失。第二种场面把 NameNode 和 DataNode 装在同一台机器上使用伪分布式配置。伪分布式的集群ID生成逻辑和全分布有些差异如果你在伪分布式环境中格式化过 NameNode然后把这份数据目录拷贝到其他 DataNode 机器上集群ID虽然一样但namespaceID会冲突导致注册失败。这种情况下需要把所有 DataNode 的current/VERSION删除后重新注册。我在实际排查中习惯把clusterID和namespaceID两个字段一起对比而不仅仅是clusterID。因为极少数情况下clusterID一样但namespaceID不一样注册同样会被拒绝。判断标准很简单两个文件里这两个字段保持一致才允许注册通过。4.3 别忽略时间同步和服务重启顺序这个问题虽然跟标题里的现象不完全一致但在排查“节点不显示”时经常会撞上。若集群内各节点系统时间相差过大DataNode 心跳时间戳会让 NameNode 觉得这个节点“迟到”了进而拒绝它加入在线列表。HDFS 对时间敏感不像某些分布式系统那样能容忍大幅时钟偏差。节点间时间差超过一定阈值时轻则出现注册异常重则引发 NameNode 认为 DataNode 失联。安装 NTP 服务或者至少手动同步时间是一个重要前置项。另外重启顺序也有讲究。严谨的做法是# 在 NameNode 所在机器上 $HADOOP_HOME/sbin/stop-dfs.sh # 确保所有机器上的进程都停了 # 再在 NameNode 所在机器上 $HADOOP_HOME/sbin/start-dfs.sh不要在 DataNode 机器上单独执行start-dfs.sh因为这会触发该机器上的所有 Hadoop 服务启动如果配置不完整会出现各种异常。统一从 NameNode 机器控制集群的启停虽然显得笨但每一步都可控排查起来也方便。4.4 Web 界面刷不出来的一个冷门原因YARN 和 HDFS 的 UI 混淆还有一个记忆特别深刻的案例。有个朋友说“hadoop图形化界面里只有一个datanode”结果我远程一看发现他打开的不是 HDFS 的 Web UI而是 YARN 的 ResourceManager 页面8088 端口。YARN 页面里压根不会显示 DataNode它显示的是 NodeManager那是调度资源用的跟 HDFS 的数据节点完全是两码事。如果你把 8088 页面当成了 HDFS 页面看到一个节点列表里只有一台机器那自然“只有一个 datanode”。确认自己打开的是哪个页面很简单看端口和页面标题。HDFS NameNode 页面通常是 9870 端口标题里有NameNodeYARN ResourceManager 页面是 8088 端口标题里有ResourceManager。正文里展示的节点表格也完全不同HDFS 界面显示的是“Datanodes”YARN 界面显示的是“Nodes”或“Active Nodes”。如果发现自己看错了页面去正确的端口刷新一下就对了。5. 防患于未然让问题不再复发的几个习惯排查完问题之后我更想跟你聊聊怎么让这个问题不再出现。毕竟集群搭起来不是一次性的后续的扩容、缩容、迁移都会碰到类似的现象。养成几个好习惯能省掉大量重复排障的时间。第一格式化 NameNode 之前先想清楚。hdfs namenode -format不是随便执行的命令每次执行都会生成新的集群ID。如果你只是想让 NameNode 重新格式化而集群里已经有一些 DataNode 了那 DataNode 侧的集群ID就必须全部清理一遍。正确的姿势是格式化 NameNode 之后要在所有 DataNode 上清理数据目录再重新启动。顺序反了就会看到这篇文章主题描述的现象。第二写一个检查脚本把每台机器的VERSION文件内容收集起来统一对比。集群规模一大手工 SSH 到每台机器上敲命令就太蠢了。你可以用一个简单的脚本把各节点的 clusterID 汇总输出for host in namenode datanode1 datanode2 datanode3; do echo $host ssh $host cat \$HADOOP_HOME/hadoop_data/hdfs/datanode/current/VERSION 2/dev/null | grep clusterID done这里的路径要和你的dfs.datanode.data.dir配置保持一致。脚本跑完一眼就能看出哪些节点 ID 对不上。平时多跑几次把输出存下来下次出问题时直接对比历史记录能快速定位是哪个节点在哪个时间点开始失联的。第三把dfs.datanode.data.dir配置里的目录权限固定好。很多次 DataNode 启动失败是因为数据目录的属主不是当前启动用户。检查一下ls -ld $HADOOP_HOME/hadoop_data/hdfs/datanode如果属主不对用chown -R修正后重启。这个问题的迷惑性在于错误信息在日志里藏得比较深不仔细看根本发现不了。第四配置参数里留一点缓冲区。HDFS 官方默认的dfs.namenode.heartbeat.recheck-interval是 5 分钟意思是如果 DataNode 5 分钟没发心跳NameNode 会把它标记为疑似失联。如果你集群里的节点经常做重启升级、网络有波动可以适当把这个值调大一点比如 10 分钟减少误报。虽然这不能解决“节点没注册”的问题但能减少“节点掉线”的误告警。最后再分享一个小技巧。如果你遇到“节点不显示”的问题又实在拿不定主意最快的路径是打开 DataNode 日志文件找到里面跟注册有关的最近一段记录直接搜索关键字Registered。DataNode 注册成功后日志里会留下一行类似Registered datanode的记录。如果你们见过这个关键字又出现在界面里那说明注册链路已经打通了如果搜索不到这行后面的节点没显示就是必然的你只需要顺着日志往上看失败原因即可。这个技巧在换了新环境、新版本或者接手别人搭的集群时尤其实用能让你在五分钟内判断出问题出在哪个环节。以上所有步骤都是我实际排查中一点点积累出来的覆盖了“图形化界面上只有一个 datanode其他节点没显示”这个问题从现象到根因再到解决的完整路径。照着逐步走一遍绝大多数情况下都能定位到问题并解决掉。Hadoop 集群说白了就是一堆进程互相通信编排Web 界面只是最外层的表象把日志和注册机制搞明白这类问题以后对你来说就是家常便饭几分钟的事。