1. 从一次告警说起Non DFS Used 到底是什么凌晨两点监控面板上那个红色的磁盘使用率数字跳到了 92%而 HDFS 自身的dfsadmin report却显示 DataNode 的 DFS Used 只有 58%。中间这三十多个百分点的差值就是今天要聊的主角——Non DFS Used。很多刚接触分布式存储运维的朋友第一次看到这个指标都会懵明明 HDFS 里没存那么多数据磁盘怎么就快满了更让人头疼的是这个空间不像普通文件那样能直接du出来删起来也没那么直观。先把概念说清楚。在 HDFS 的 DataNode 视角里一块数据盘的空间被划分成几块真正被 HDFS 块文件占用的叫DFS Used预留出来给副本、快照、回收站等用的叫DFS Remaining而既不属于 HDFS 块文件、又实实在在占着磁盘的那部分就是Non DFS Used。它的计算公式在源码里写得很直白Non DFS Used Configured Capacity - DFS Used - DFS Remaining注意这里的Configured Capacity是 DataNode 配置的数据目录所在磁盘的总容量而不是整块物理盘。所以 Non DFS Used 本质上是一个兜底差值——凡是 DataNode 算不明白、但又确实被占用的空间都会被归到它头上。这就解释了为什么它经常是个背锅侠日志文件、临时文件、被删除但句柄未释放的文件、其他进程写的数据、甚至文件系统本身的元数据都可能被算进去。我见过太多人一看到 Non DFS Used 高第一反应就是去 HDFS 里删数据结果删了半天指标纹丝不动。原因很简单这部分空间压根不在 HDFS 的管理范围内。要真正解决问题得先搞清楚它到底被谁吃了。下面这张表是我在实际排查中总结的常见来源可以先对照着定位方向来源类型典型表现排查手段系统日志/var/log持续增长du -sh /var/log/*临时文件/tmp、/var/tmp堆积ls -lht /tmp已删除未释放lsof能看到 deleted 标记lsof | grep deleted其他服务数据同盘部署了别的组件du -sh /*逐层排查文件系统保留块ext4 默认保留 5%tune2fs -l查看快照/备份残留快照目录占用查看快照策略理解了这个指标的兜底性质后面的排查思路就顺了既然它是差值那我们要做的就是把这个差值一点点拆开找到真正占用空间的那个元凶。这也是为什么我常说Non DFS Used 清理不是单纯的删文件而是一次完整的磁盘占用溯源。2. 别急着删数据先建立正确的排查顺序很多人处理这类问题的习惯很不好——上来就rm -rf删完发现没效果再删最后把有用的东西也删了。我在早期也犯过这个错有一次直接把一个还在被进程写入的日志文件删了结果空间没释放服务还因为找不到文件句柄报了一堆错。所以这里必须先讲清楚排查顺序顺序错了后面全是白费功夫。2.1 第一步永远是确认指标口径在动手之前先用 DataNode 的 JMX 或者hdfs dfsadmin -report把几个关键数字拉出来对齐。重点看三个值Configured Capacity、DFS Used、Non DFS Used。有时候你会发现 Non DFS Used 是负数这通常意味着 DataNode 的容量配置和实际磁盘对不上比如配置里写的是 500G实际盘只有 400G或者多个数据目录跨了不同大小的盘。这种情况不是空间被占用而是配置错误得先去改dfs.datanode.data.dir的配置。还有一种情况是刚扩容完新盘DataNode 还没完成块扫描指标会短暂失真。这时候别急着操作等一轮block report跑完再看。我一般会观察 10 到 15 分钟确认数字稳定了再进入下一步。2.2 第二步用 df 和 du 做交叉验证df -h看的是文件系统层面的真实占用du -sh看的是目录累加的大小。这两个数字经常对不上而对不上的那部分往往就是 Non DFS Used 的重要线索。举个我实际遇到的例子df显示某块盘用了 80%但du -sh /data加起来只有 50%。中间 30% 去哪了后来用lsof | grep deleted一查发现是一个被删除但进程还在写的日志文件占了将近 200G。这里有个经验du 统计的是目录树里当前存在的文件df 统计的是文件系统实际分配的块。所以当两者差异巨大时优先怀疑已删除未释放和稀疏文件这两类情况。稀疏文件比较隐蔽du默认按实际占用算df按逻辑大小算用du --apparent-size才能看出来。2.3 第三步才是逐层定位大目录确认了差异存在再开始逐层往下钻。我的习惯是从根目录开始用du -h --max-depth1 /一层层缩小范围。注意不要一上来就对整个盘做du数据量大时能跑几个小时还拖慢 IO。可以先用du -h --max-depth1快速定位到某个大目录再针对那个目录深入。排查过程中有个小技巧用ncdu这个工具会比du直观很多它能交互式地展示目录占用还能直接在里面删文件。不过生产环境不一定装得了所以du的组合命令还是得熟练。下面是我常用的一套命令可以直接抄# 查看各挂载点使用率 df -h # 查看根目录下各一级目录占用 du -h --max-depth1 / 2/dev/null | sort -rh | head -20 # 查找已删除但未释放的文件 lsof | grep deleted | awk {print $7, $2, $1, $9} | sort -rn | head -20 # 查看文件系统保留块比例 tune2fs -l /dev/sdX | grep -i reserved注意lsof | grep deleted在文件句柄特别多的机器上会很慢建议配合timeout使用避免卡死终端。把这三步走完基本就能锁定 Non DFS Used 的大致来源了。接下来才是针对性地清理而不是盲目删数据。3. 逐类击破Non DFS Used 的六大常见来源与处理定位到方向之后就要按类型来处理了。不同类型的占用清理方式和风险等级完全不同。我按处理难度和常见程度排了个序从最容易处理的开始讲。3.1 系统日志与临时文件最容易被忽视的温水煮青蛙系统日志是 Non DFS Used 里最典型的慢性增长来源。/var/log下的日志如果不做轮转几个月就能吃掉几十上百 G。尤其是那些开了 debug 级别的服务日志增长速度非常夸张。我见过一台机器因为某个组件日志级别配错三天写了 400G 日志直接把盘撑满。处理这类问题核心不是删而是配置轮转。logrotate是标准方案但很多人配了之后没验证结果轮转规则写错了日志还是无限增长。我的建议是配完之后手动跑一次logrotate -f /etc/logrotate.d/xxx确认切割和压缩都正常。临时文件方面/tmp和/var/tmp是两个重灾区。有些程序退出时不清理自己的临时文件日积月累就堆起来了。可以写个定时任务定期清理超过 7 天没被访问的临时文件find /tmp -type f -atime 7 -delete find /var/tmp -type f -atime 7 -delete但要注意有些服务的 socket 文件或者锁文件放在/tmp里删了会导致服务异常。所以清理前最好先ls看一眼确认没有正在使用的文件。我一般会先跑find不带-delete把要删的列出来人工过一遍确认没问题再加删除动作。3.2 已删除未释放的文件空间假释放的元凶这是最让人抓狂的一类。文件明明删了du也看不到但df显示空间没回来。原因是有进程还持有这个文件的句柄Linux 的文件系统只有在所有句柄都关闭后才会真正释放块。这种情况在日志文件上尤其常见——运维用rm删了日志但写日志的进程没重启句柄还在空间就一直占着。排查方法前面提过用lsof | grep deleted。找到之后有两种处理方式一是重启持有句柄的进程让它释放二是如果不想重启可以用 /proc/PID/fd/FD的方式清空文件内容这样句柄还在但空间能释放出来。第二种方式更温和适合不能随便重启的核心服务。# 找到占用大文件的进程和文件描述符 lsof | grep deleted | sort -k7 -rn | head # 清空该文件描述符对应的内容谨慎操作 : /proc/12345/fd/67注意第二种方式本质上是把文件截断为 0如果进程还在往里写会从 0 开始继续写。对于日志类文件没问题但对于正在被读取的数据文件可能导致数据损坏操作前务必确认文件类型。我个人的经验是与其事后清理不如事前规范。日志文件一律用logrotate管理不要手动rm需要清理时用truncate -s 0而不是rm这样句柄不会失效空间也能立即释放。3.3 同盘部署的其他服务最容易被忽略的邻居很多集群为了省机器会把 DataNode 和其他服务部署在同一块盘上。比如把 Kafka 的日志目录、Elasticsearch 的数据目录、或者某个数据库的数据文件放在 DataNode 的数据盘上。这些服务的数据对 HDFS 来说就是 Non DFS Used而且它们往往增长很快。这种情况的排查方法是看 DataNode 数据目录的挂载点然后du这个挂载点的根目录看看除了 DataNode 的数据目录之外还有哪些目录在占空间。我遇到过一次某台机器的 Non DFS Used 高达 40%最后发现是同盘的 Kafka 日志没配清理策略堆积了 2T 多。处理方式有两种短期是给这些服务配置清理策略或者迁移数据长期是做好磁盘规划DataNode 的数据盘尽量专用不要和其他 IO 密集型服务混部。如果实在要混部至少给每个服务设置磁盘配额避免某一个服务把盘吃满影响 HDFS。3.4 文件系统保留块ext4 默认吃掉 5%这个点很多人不知道。ext4 文件系统默认会给 root 保留 5% 的空间用于防止普通用户把盘写满导致系统无法运行。对于一块 4T 的盘5% 就是 200G。这部分空间df会算进 Used但du看不到所以也会被归到 Non DFS Used 里。查看保留块比例tune2fs -l /dev/sdX | grep -i reserved block count如果是专门给 DataNode 用的数据盘可以把保留比例调低比如调到 1%tune2fs -m 1 /dev/sdX这样能释放出 4% 的空间。不过要注意调低保留块后如果盘真的写满了root 用户也可能无法写入影响系统稳定性。所以这个操作适合那些有独立监控、能及时告警的数据盘不建议在系统盘上做。3.5 快照与备份残留看不见的时间胶囊如果 DataNode 的数据目录所在文件系统开了快照功能比如 LVM 快照、ZFS 快照、或者某些商业存储的快照那么快照会占用额外的空间。这些空间对 HDFS 不可见但实实在在占着盘。快照的特点是写时复制原数据被修改时旧数据块会被保留在快照里所以快照越多、保留时间越长占用越大。排查方法是看存储层面有没有快照策略以及快照的实际占用。不同存储的查看方式不一样LVM 用lvsZFS 用zfs list -t snapshot。处理方式就是清理过期快照或者调整快照保留策略。这个操作一般在存储层面做需要和存储管理员配合。3.6 稀疏文件与预分配文件逻辑大小和实际占用的差异有些应用会创建稀疏文件或者预分配文件比如数据库的数据文件、虚拟机的磁盘镜像。这类文件的特点是逻辑大小很大但实际占用的块可能很少。du默认显示实际占用df显示的是文件系统分配的块两者会有差异。如果应用预分配了空间但没实际写入df会显示已占用但du看不到。排查这类文件可以用# 查找实际占用远小于逻辑大小的文件 find /data -type f -size 1G -exec du -h {} \; | sort -rh | head对比ls -lh和du -h的结果如果差异很大就是稀疏文件。处理方式取决于应用一般不建议直接删而是联系应用负责人确认是否可以清理或迁移。4. 一次完整的清理实战从 92% 降到 65%光讲理论不够我把最近一次实际处理的完整过程复盘一下。这次的情况比较典型涵盖了上面说的好几类来源可以当作一个综合案例来看。4.1 现场情况与初步判断某天下午收到告警一批 DataNode 的磁盘使用率超过 90%但 HDFS 的 DFS Used 只有 55% 左右。登录其中一台机器先跑df -h和hdfs dfsadmin -report对齐数据Filesystem Size Used Avail Use% Mounted on /dev/sdb1 3.6T 3.3T 120G 97% /data1DataNode 报告显示这块盘的 Configured Capacity 是 3.6TDFS Used 是 2.0TDFS Remaining 是 1.2T算下来 Non DFS Used 大约是 0.4T。但df显示 Used 是 3.3T中间差了 1.3T。这说明除了 Non DFS Used还有一部分空间是账面对不上的需要进一步排查。4.2 逐层定位找到三个元凶第一步用du看/data1下各目录占用du -h --max-depth1 /data1 2/dev/null | sort -rh结果发现 DataNode 的数据目录占了 2.0T和 DFS Used 对得上。但/data1下还有一个kafka-logs目录占了 800G。这就是第一个元凶——同盘部署的 Kafka 日志。第二步用lsof | grep deleted查已删除未释放的文件发现一个被删除的日志文件占了 300G持有句柄的是一个没重启的老进程。这是第二个元凶。第三步检查文件系统保留块发现 ext4 默认保留了 5%也就是 180G。这是第三个元凶。三项加起来800G 300G 180G 1.28T和之前算出来的 1.3T 差异基本吻合。问题定位完成。4.3 清理操作与验证针对三个元凶分别处理Kafka 日志方面先确认 Kafka 的日志保留策略发现配的是 7 天但实际没生效因为清理线程被某个异常阻塞了。重启 Kafka 的清理线程后手动触发了一次清理释放了 600G。同时把保留策略调整为 3 天并加了监控。已删除未释放的文件方面确认那个进程不是核心服务后重启了进程300G 空间立即释放。如果当时不能重启我会用truncate的方式处理。文件系统保留块方面把数据盘的保留比例从 5% 调到 1%释放了约 144G。全部处理完再次df -hFilesystem Size Used Avail Use% Mounted on /dev/sdb1 3.6T 2.3T 1.2T 65% /data1使用率从 97% 降到了 65%Non DFS Used 也从 0.4T 降到了 0.1T 左右。整个过程没有删除任何 HDFS 数据全部是通过清理非 HDFS 占用实现的。4.4 这次实战的几个关键经验第一先对齐指标再动手。如果一上来就删 HDFS 数据不仅解决不了问题还可能造成数据丢失。第二du 和 df 的差异是重要线索差异越大说明账外占用越多。第三同盘混部是万恶之源能专用就专用不能专用就要做好配额和监控。第四保留块这种隐形占用要提前规划建盘时就把比例调好别等出问题了再改。5. 防患于未然让 Non DFS Used 不再失控清理是治标预防才是治本。Non DFS Used 之所以容易失控根本原因是它不在 HDFS 的管理范围内没有天然的清理机制。所以必须靠运维规范来兜底。下面是我总结的几条实践建议都是踩过坑之后沉淀下来的。5.1 磁盘规划DataNode 数据盘尽量专用这是最有效的一条。DataNode 的数据盘就只放 HDFS 数据不要混部其他服务。如果资源实在紧张至少要把日志、临时文件这些高增长的东西放到独立的盘上。我现在的习惯是每台 DataNode 至少配两块盘一块专门给 DataNode一块给系统和日志。这样即使日志爆了也不会影响 HDFS。如果必须混部一定要给每个服务设置磁盘配额。Linux 的quota或者 cgroup 的blkio都能做虽然配置麻烦点但比事后清理省心得多。5.2 监控体系把 Non DFS Used 纳入日常告警很多人只监控磁盘使用率不监控 Non DFS Used。这导致问题发现时往往已经很严重了。我的做法是把 Non DFS Used 的绝对值和使用率都纳入监控设置两级告警超过 100G 或者超过磁盘容量 10% 时预警超过 200G 或者 20% 时严重告警。采集方式可以用 DataNode 的 JMX 接口也可以用hdfs dfsadmin -report解析。Prometheus 生态里有现成的 HDFS exporter配置好就能直接出图。关键是告警阈值要根据集群规模调整小集群 100G 可能就很大了大集群可能 500G 才值得关注。5.3 日志规范统一用 logrotate禁止手动 rm日志是 Non DFS Used 最常见的来源所以日志管理必须规范。所有服务的日志都要配logrotate并且要验证轮转生效。轮转策略建议按大小和天数双条件触发比如单文件超过 500M 或者超过 1 天就轮转保留 7 天压缩存储。还有一条铁律永远不要手动rm正在被写入的日志文件。要清理就用truncate -s 0或者通过 logrotate 的copytruncate模式。这样能避免已删除未释放的问题。5.4 定期巡检每月做一次磁盘占用盘点再好的自动化也替代不了人工巡检。我建议每月做一次磁盘占用盘点重点看几个东西Non DFS Used 的变化趋势、/var/log和/tmp的增长情况、有没有新的服务混部到数据盘上、快照策略有没有产生意外占用。巡检不用太复杂写个脚本把关键指标拉出来人工过一眼就行。关键是形成习惯别等告警了才去看。我见过太多团队平时不管一出问题就是紧急故障其实很多问题在巡检时就能发现苗头。5.5 容量规划给 Non DFS Used 留出预算做容量规划时不能只算 HDFS 数据增长还要给 Non DFS Used 留出空间。我的经验是至少预留 15% 到 20% 的磁盘空间给非 HDFS 占用。如果混部了其他服务预留比例还要更高。这样即使 Non DFS Used 增长也不会立即触发磁盘告警给处理留出缓冲时间。具体到每个集群预留比例可以根据历史数据来定。比如过去半年 Non DFS Used 平均占 8%峰值到过 15%那规划时就按 20% 预留留足安全边际。6. 几个容易踩的坑和我的应对心得最后这部分我想聊几个具体操作中容易踩的坑。这些都是我在实际处理中交过学费的写出来希望能帮大家少走弯路。第一个坑是误判 Non DFS Used 为负数。前面提过这通常是容量配置错误导致的。但还有一种情况是 DataNode 刚启动块扫描还没完成指标会短暂异常。这时候不要急着改配置先等一轮扫描完成。如果扫描完还是负数再去检查dfs.datanode.data.dir的配置和实际磁盘是否匹配。第二个坑是用du排查时忽略了挂载点。du默认会跨文件系统统计如果数据目录下挂了别的盘du会把挂载点的内容也算进去导致结果失真。正确的做法是用du -x限制在同一个文件系统内或者用--exclude排除挂载点。第三个坑是清理快照时没确认依赖。有些快照是备份策略的一部分直接删可能导致备份链断裂。清理前一定要确认快照的用途和保留策略最好和相关负责人确认后再操作。第四个坑是调整保留块后忘记更新监控。把保留块从 5% 调到 1% 后磁盘的实际可用空间变了但监控阈值如果没同步调整可能会出现误告警或者漏告警。每次调整磁盘相关配置后都要同步检查监控规则。第五个坑是在业务高峰期做清理。清理操作本身会消耗 IO如果在大促或者业务高峰期做可能影响 HDFS 读写性能。我的习惯是安排在业务低峰期并且分批操作不要一次性对所有节点动手。说到底Non DFS Used 的清理不是什么高深技术核心就两点搞清楚它是什么按正确的顺序排查。它本质上是一个差值指标是 DataNode 算不明白的那部分空间。只要掌握了df和du的交叉验证方法再配合lsof和文件系统工具绝大多数情况都能定位到具体原因。真正难的不是技术而是养成规范的运维习惯——磁盘专用、日志轮转、定期巡检、容量预留。这些做到了Non DFS Used 就不会再成为半夜告警的常客。