处理 df 和 du 数据不一致的问题
今日有大数据团队人员巡检时发现一台 datanode 节点上有一块硬盘出现了异常高占用情况,遂使用 du 命令进行排查,发现 du 显示的统计结果和 df 显示的统计结果不一致,遂协助其进行问题分析。
问题分析
问题截图如下:
此问题网上目前有比较常见的几种问题分析及解决办法如下:
-
预留空间 为了预防紧急情况,linux ext 文件系统会预留部分硬盘空间,具体预留的数值可以通过
tune2fs -l [dev_name] | grep "Reserved block count"
查看到(dev_name是设备名),这里预留的空间会被df 计算到已用空间中,从而导致 df 和 du 统计不一致。如果需要调整预留空间大小, 我们可以使用tune2fs -m [size] [dev_name]
来进行调整。 -
幻影文件(phantom file) du 是统计被文件系统记录到的每个文件的大小,然后进行累加得到的大小,这是通过文件系统获取到的。而 df 主要是从超级块(superblock) 中读入硬盘使用信息,df 获取到的是磁盘块被使用的情况。当一个文件被删除时,如果有别的进程正在使用它(占有句柄), 这个文件将不会被 du 统计到,但是这个文件被占用的磁盘空间却依然会被 df 统计到。这些文件,以及正在使用这些文件的进程可以通过
lsof | grep deleted
查到。当进程停止或者被 kill 时,这些空间将被释放。 -
未统计到的文件 当我们将一个目录挂在到一个新的设备(硬盘)上之前,如果这个 目录里面已经有数据,那么这一部分数据不会被 du 感知,在文件系统中也看不到这些数据,但是这些数据又是确实占用了磁盘空间,是能够被 df 所统计到的。这时候通过 du/df 统计原设备的空间使用情况,就会发现 df 统计到的比 du 要多。遇到这样的情况时,使用
fuser -km [directory]
杀死占用该目录的所有进程(小心操作!),然后使用umount [directory]
将该目录挂载的设备卸载,这时,目录里面原来已有的数据就会出现,我们将其删除之后,再重新挂载设备(mount -t [type] [dev] [directory]
)即可。
通过分析,发现我们的情况,不符合以上几种常见的问题,所以只能自己找答案。
经过查询 inode 占用情况,以及跟正常磁盘的对比,发现该盘 du 和 df 的 inode 统计都是相同的,应该不存在多统计文件或少统计文件的情况,如图:
另,在进行 tune2fs -l /dev/sdc1
时,在参数底部,发现磁盘有错误,报错如下:
说明该磁盘在2019年的时候已经存在问题,当时刚好有过一次断电重启,估计就是那次重启,导致数据块损坏,空间无法释放。Last error function: ext4_wait_block_bitmap
也佐证了这一点,说明 block bitmap 里的内容无法读取。
具体分析可参考大神的文章:ext4块分配机制及源码分析
嗯,剩下的就是要修复磁盘了。
解决问题
- 首先就是停掉该 datanode 的业务,并下线节点,停止进程,备份数据……
- 使用
umount /dev/sdc1;
卸载硬盘; - 使用
fsck -t ext4 /dev/sdc1;
进行磁盘修复,修复过程中可能会出现块无法读取,需要强制覆盖的提示,如下图:如果不想手动确认的话,可以使用
fsck -t ext4 /dev/sdc1 -y;
跳过提醒。 - 修复完成后,使用
mount /dev/sdc1 /data03;
重新挂载; - 再次使用
tune2fs -l /dev/sdc1
及df
检查数据,发现空间使用正常,磁盘也没有报错了。 - 启动 datanode 进程,上线 datanode ,数据校验,未发现错误。
Done!