☰
HDFS Non DFS Used 磁盘告警排查:从原理到清理预防实战
2026/10/16 7:26:19 网站建设 项目流程

1. 一次磁盘告警引发的排查:Non DFS Used 到底是什么

凌晨两点,监控平台弹出一条告警:某集群 DataNode 节点磁盘使用率突破 90% 阈值。按照常规思路,我第一反应是数据写入量激增,于是登录节点执行df -h查看磁盘占用,发现数据盘确实快满了。但接下来的一幕让我有点意外——打开 HDFS 的 Web UI,看到 DFS Used 只占了不到 60%,剩余空间却显示为 "Non DFS Used" 占了大头。

这个 "Non DFS Used" 是 HDFS 运维里一个非常经典但又容易被忽视的概念。简单说,它指的是 DataNode 数据目录所在磁盘上,不属于 HDFS 管理范围的那部分空间占用。HDFS 自己算账的逻辑是这样的:磁盘总容量减去 DFS Used(HDFS 实际存储的数据块),再减去 Reserved(系统保留空间),剩下的就是 Non DFS Used。公式写出来就是:

Non DFS Used = 磁盘总容量 - DFS Used - Reserved Space - 剩余可用空间

换句话说,只要磁盘上存在任何 HDFS 之外的文件,比如日志、临时文件、被删除但句柄未释放的文件、甚至是其他程序写入的数据,都会被归入 Non DFS Used。这个指标本身不是"错误",但它一旦异常膨胀,就意味着 DataNode 可用的写入空间被蚕食,严重时直接导致写入失败、数据块副本丢失,甚至节点被踢出集群。

这篇文章适合所有负责 HDFS 集群运维的工程师、大数据平台开发者,以及正在被"磁盘满了但 HDFS 显示没满"这类问题困扰的同行。我会把这次排查的完整过程拆开讲清楚:Non DFS Used 的计算原理、常见成因、排查手段、清理方案,以及后续如何建立预防机制。内容基于真实运维场景整理,涉及的命令和参数都可以直接拿去用。

2. Non DFS Used 的计算逻辑与常见成因拆解

2.1 HDFS 是如何统计这块空间的

要理解 Non DFS Used,得先搞清楚 DataNode 上报磁盘信息的机制。DataNode 定期向 NameNode 发送心跳时,会附带一份StorageReport,里面包含capacity、dfsUsed、remaining、nonDfsUsed等字段。NameNode 的 Web UI 和dfsadmin report命令展示的数据就来源于此。

关键在于nonDfsUsed的计算方式。在较新的 Hadoop 版本中,DataNode 通过DF命令(或等效的系统调用)获取整个磁盘分区的使用情况,然后用分区总容量减去 HDFS 数据目录实际占用的字节数,得到的就是 Non DFS Used。这里有个容易踩的坑:如果多个数据目录共享同一个磁盘分区,HDFS 会把整个分区的非 HDFS 占用都算进来,而不是只算某个目录。

举个例子,假设/data分区挂载了 1TB 磁盘,HDFS 的dfs.datanode.data.dir配置为/data/dfs/dn,同时这个分区上还跑着 YARN 的本地临时目录/data/yarn/local。那么 YARN 产生的所有临时文件、容器日志、Shuffle 数据,全部会被计入 Non DFS Used。这就是为什么很多集群明明 HDFS 数据不多,Non DFS Used 却高得吓人。

2.2 六种最常见的空间占用来源

结合我这些年处理过的案例,Non DFS Used 异常膨胀的原因基本逃不出下面这几类:

成因类别典型表现排查难度
日志文件堆积DataNode/NodeManager 日志未轮转,单文件达数十 GB低
被删除但未释放的文件lsof显示 deleted 状态,进程仍持有句柄中
YARN 本地临时目录容器工作目录、Shuffle 数据残留低
其他服务共用磁盘同一分区部署了非 HDFS 组件低
文件系统保留空间ext4 默认 5% 保留给 root低
快照或副本残留存储快照、回收站未清理中

其中被删除但未释放的文件是最隐蔽的一类。Linux 的文件删除机制是:只有当所有持有该文件句柄的进程都关闭文件后,磁盘空间才会真正释放。如果某个进程(比如一个卡死的 DataNode 或外部脚本)一直持有大文件的句柄,即使rm删除了文件,df依然显示空间被占用,而du却统计不到。这种"幽灵占用"经常让人抓狂。

2.3 为什么这个指标值得单独关注

很多人觉得 Non DFS Used 只是个参考值,不影响 HDFS 运行。这个认知是危险的。DataNode 在决定是否接受新数据块写入时,会检查可用空间是否低于配置的阈值(dfs.datanode.du.reserved)。如果 Non DFS Used 吃掉了大量空间,实际可用于 HDFS 写入的空间就会缩水,触发DiskOutOfSpaceException,导致写入失败。

更严重的情况是,当 Non DFS Used 持续增长,DataNode 可能因为磁盘满而无法写入新的数据块副本,NameNode 检测到副本数不足后会触发副本复制,但其他节点如果也有同样问题,就会形成连锁反应。我见过一次因为日志把磁盘写满,导致整个机架的数据块副本同时丢失的案例,恢复起来相当痛苦。

3. 实战排查:从告警到定位真凶的完整过程

3.1 第一步:确认 Non DFS Used 的真实数值

登录问题节点后,不要急着删文件。先用几个命令交叉验证,把账算清楚:

# 查看磁盘整体使用情况 df -h /data # 查看 HDFS 数据目录实际占用 du -sh /data/dfs/dn # 通过 hdfs 命令查看集群视角的统计 hdfs dfsadmin -report | grep -A 10 "DataNode"

df显示的是文件系统层面的占用,du显示的是目录实际占用。如果两者差距巨大,基本可以确定存在"被删除但未释放"的文件。这时候用lsof找出持有句柄的进程:

# 查找所有 deleted 状态但仍被占用的文件 lsof | grep deleted | grep /data # 按占用大小排序,快速定位大文件 lsof | grep deleted | awk '{print $7, $9}' | sort -rn | head -20

这一步的输出会告诉你哪个进程、哪个文件在"占着茅坑不拉屎"。常见的是 DataNode 自身的日志文件被外部工具轮转后,进程没有重新打开新文件,导致旧文件句柄一直挂着。

3.2 第二步:逐层排查目录占用

如果df和du的数值基本吻合,说明空间确实被实际文件占用了,那就需要逐层定位。我的习惯是从分区根目录开始,用du按层级下钻:

# 查看一级目录占用,按大小排序 du -h --max-depth=1 /data | sort -rh # 对占用最大的目录继续下钻 du -h --max-depth=1 /data/yarn | sort -rh

这次排查中,我发现/data/yarn/local目录占了将近 200GB。进一步查看发现,里面堆满了usercache下的容器工作目录,很多是几个月前失败的作业残留。YARN 的本地目录清理依赖yarn.nodemanager.localizer.cache.cleanup.interval-ms和yarn.nodemanager.localizer.cache.target-size-mb两个参数,如果配置不当或者 NodeManager 长时间未重启,残留就会越积越多。

3.3 第三步:检查文件系统保留空间

还有一个容易被忽略的点是文件系统的保留块。ext4 默认会保留 5% 的空间给 root 用户,这部分空间在df里算作已使用,但普通进程无法写入。对于一块 4TB 的盘,5% 就是 200GB,相当可观。

# 查看文件系统保留比例 tune2fs -l /dev/sdX | grep -i reserved # 调整保留比例(生产环境谨慎操作,建议保留 1%-2%) tune2fs -m 1 /dev/sdX

对于专门用于 HDFS 的数据盘,把保留比例降到 1% 是常见做法,但要注意这会影响系统在磁盘满时的应急能力,需要权衡。

3.4 第四步:确认 HDFS 自身的 Reserved 配置

别忘了 HDFS 自己也有一层保留空间配置dfs.datanode.du.reserved,默认值是 10GB 左右。这个值会从可用空间中扣除,不参与 HDFS 写入。如果这个值设置得过大,也会让 Non DFS Used 看起来偏高。检查hdfs-site.xml中的配置:

<property> <name>dfs.datanode.du.reserved</name> <value>10737418240</value> <!-- 10GB --> </property>

这个值的设定要根据磁盘容量和业务写入速度来定。太小了容易写满,太大了浪费空间。我的经验是,对于 4TB 以上的盘,保留 20-30GB 比较稳妥,给系统留出应急缓冲。

4. 清理方案与操作避坑指南

4.1 安全清理 YARN 本地目录

确认是 YARN 残留后,不要直接rm -rf整个目录,那样可能误删正在运行的容器数据。正确做法是先停止 NodeManager,或者通过 YARN 提供的清理机制处理:

# 优雅方式:重启 NodeManager,触发自动清理 yarn-daemon.sh stop nodemanager yarn-daemon.sh start nodemanager # 手动清理时,只删除超过一定天数的目录 find /data/yarn/local/usercache -type d -mtime +7 -exec rm -rf {} \;

注意:手动清理前务必确认没有正在运行的作业,否则会导致容器失败。建议在业务低峰期操作,并提前通知相关团队。

4.2 处理被删除但未释放的文件

对于lsof找到的 deleted 文件,处理方式取决于持有句柄的进程:

  • 如果是 DataNode 自身持有,最安全的做法是重启 DataNode。重启前先执行hdfs dfsadmin -refreshNodes确认节点状态,然后优雅停止。
  • 如果是外部脚本或工具持有,先尝试正常终止该进程。如果进程卡死无法终止,再考虑强制 kill,但要评估对业务的影响。
  • 极端情况下,可以用> /proc/PID/fd/FD的方式清空文件内容,但这只适用于普通文件,且需要 root 权限。
# 查看进程持有的具体文件描述符 ls -l /proc/PID/fd | grep deleted # 清空文件内容(谨慎使用) : > /proc/PID/fd/FD_NUMBER

4.3 日志轮转配置优化

日志堆积是最常见的成因,也是最容易预防的。检查 DataNode 和 NodeManager 的日志配置,确保启用了按大小和时间的轮转:

<!-- log4j.properties 关键配置 --> log4j.appender.RFA.MaxFileSize=256MB log4j.appender.RFA.MaxBackupIndex=10

同时配合系统的logrotate,设置合理的保留天数和压缩策略。我一般会把 HDFS 相关日志的保留周期设为 7-14 天,超过的自动压缩归档到冷存储。这样既能满足排查需求,又不会让磁盘被日志撑爆。

4.4 清理操作的检查清单

每次清理前,我都会过一遍这个清单,避免手抖:

  1. 确认当前没有正在运行的写入作业,或已通知相关方
  2. 确认要删除的目录不属于 HDFS 数据目录
  3. 确认删除操作不会影响其他共用该磁盘的服务
  4. 删除前记录当前磁盘使用率,便于对比效果
  5. 删除后立即用df -h和 HDFS UI 确认 Non DFS Used 是否下降
  6. 观察 24 小时,确认没有异常增长

5. 预防机制:让 Non DFS Used 不再失控

5.1 监控指标的精细化配置

光靠磁盘使用率告警是不够的,需要把 Non DFS Used 单独拎出来监控。在监控系统中添加如下指标采集:

  • nonDfsUsed绝对值及其占磁盘总容量的比例
  • nonDfsUsed的日环比增长率
  • DFS Used 与 Non DFS Used 的比值变化趋势

我一般会设置两级阈值:Non DFS Used 占比超过 20% 触发警告,超过 30% 触发严重告警。这样能在问题恶化前就介入处理。

5.2 磁盘规划的最佳实践

从架构层面,最有效的预防手段是磁盘隔离。不要让 HDFS 数据目录和其他服务共用同一个分区。理想情况下:

  • HDFS 数据盘单独挂载,只放dfs.datanode.data.dir
  • YARN 本地目录放在独立的盘或分区
  • 日志目录单独挂载,避免日志写满影响数据盘

如果资源有限无法完全隔离,至少要在dfs.datanode.du.reserved中预留足够的缓冲空间,并严格控制共用服务的写入量。

5.3 定期巡检脚本

我写了一个简单的巡检脚本,每周跑一次,输出各节点的 Non DFS Used 排名和异常目录:

#!/bin/bash # 巡检 Non DFS Used 异常节点 for node in $(cat datanode_list.txt); do echo "=== $node ===" ssh $node "df -h /data | tail -1; du -h --max-depth=1 /data 2>/dev/null | sort -rh | head -5" done

这个脚本能快速发现哪些节点的非 HDFS 占用在增长,以及增长来自哪个目录。配合定时任务,可以做到早发现早处理。

5.4 版本升级带来的变化

值得一提的是,Hadoop 3.x 版本对 Non DFS Used 的统计做了一些优化,引入了更精确的nonDfsUsed计算方式,减少了因多目录共享分区导致的误报。如果还在用 2.x 版本,升级到 3.x 能省不少心。不过升级前要做好兼容性测试,特别是涉及存储格式和 API 变更的部分。

6. 几个真实踩坑案例的复盘

6.1 案例一:日志轮转脚本的副作用

某次集群扩容后,新节点的 Non DFS Used 在三天内从 5% 涨到 40%。排查发现是运维团队部署的日志轮转脚本有 bug,轮转后没有通知 DataNode 重新打开日志文件,导致旧日志句柄一直被持有。lsof显示有十几个 deleted 状态的日志文件,加起来超过 300GB。重启 DataNode 后空间立即释放。这个案例的教训是:任何涉及文件句柄的操作,都要考虑对运行中进程的影响。

6.2 案例二:YARN 缓存配置的坑

另一个集群的 Non DFS Used 缓慢增长,每周增加约 50GB。查下来是 YARN 的本地化缓存清理间隔设置得太长(默认 10 分钟,但被改成了 24 小时),加上target-size-mb设置过大,导致缓存文件长期不清理。调整参数后,Non DFS Used 稳定在 10% 以内。这里的关键是理解每个参数的实际含义,不要盲目照搬网上的配置。

6.3 案例三:快照导致的隐性占用

有个节点 Non DFS Used 异常高,但du和lsof都找不到明显的大文件。最后发现是存储层做了快照,快照数据占用了大量空间,而du默认不统计快照。用lvs和vgs查看逻辑卷信息后确认了问题。处理方式是清理过期快照,并调整快照策略。这个案例提醒我们,排查要穿透到存储层,不能只看文件系统层面。

7. 写在最后的一些个人体会

处理 Non DFS Used 这类问题,最忌讳的就是一上来就删文件。我见过太多因为着急清理而误删数据、导致集群故障的案例。正确的姿势永远是:先算清楚账,再定位来源,最后才动手清理。df、du、lsof这三个命令的组合,能解决 90% 以上的磁盘占用排查问题。

另外,Non DFS Used 本身不是敌人,它是 HDFS 给我们的一个信号——提醒我们磁盘上还有其他东西在占用空间。与其把它当成需要消灭的指标,不如把它当成一个健康检查项,定期关注它的变化趋势。只要它稳定在一个合理范围内,就说明集群的磁盘管理是健康的。

最后分享一个小技巧:在 DataNode 的hdfs-site.xml中,可以配置多个数据目录,并把它们分散到不同的物理磁盘上。这样即使某块盘出现 Non DFS Used 异常,也不会影响整个节点的写入能力。这个配置在集群规划阶段就要考虑好,后期调整成本会高很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询