处理 df 和 du 数据不一致的问题

今日有大数据团队人员巡检时发现一台 datanode 节点上有一块硬盘出现了异常高占用情况,遂使用 du 命令进行排查,发现 du 显示的统计结果和 df 显示的统计结果不一致,遂协助其进行问题分析。

问题分析

问题截图如下:

29cc9ba1b06c423580b4a043d23fb8bc.png

此问题网上目前有比较常见的几种问题分析及解决办法如下:

  1. 预留空间 为了预防紧急情况,linux ext 文件系统会预留部分硬盘空间,具体预留的数值可以通过 tune2fs -l [dev_name] | grep "Reserved block count" 查看到(dev_name是设备名),这里预留的空间会被df 计算到已用空间中,从而导致 df 和 du 统计不一致。如果需要调整预留空间大小, 我们可以使用 tune2fs -m [size] [dev_name] 来进行调整。

  2. 幻影文件(phantom file) du 是统计被文件系统记录到的每个文件的大小,然后进行累加得到的大小,这是通过文件系统获取到的。而 df 主要是从超级块(superblock) 中读入硬盘使用信息,df 获取到的是磁盘块被使用的情况。当一个文件被删除时,如果有别的进程正在使用它(占有句柄), 这个文件将不会被 du 统计到,但是这个文件被占用的磁盘空间却依然会被 df 统计到。这些文件,以及正在使用这些文件的进程可以通过 lsof | grep deleted 查到。当进程停止或者被 kill 时,这些空间将被释放。

  3. 未统计到的文件 当我们将一个目录挂在到一个新的设备(硬盘)上之前,如果这个 目录里面已经有数据,那么这一部分数据不会被 du 感知,在文件系统中也看不到这些数据,但是这些数据又是确实占用了磁盘空间,是能够被 df 所统计到的。这时候通过 du/df 统计原设备的空间使用情况,就会发现 df 统计到的比 du 要多。遇到这样的情况时,使用 fuser -km [directory] 杀死占用该目录的所有进程(小心操作!),然后使用 umount [directory] 将该目录挂载的设备卸载,这时,目录里面原来已有的数据就会出现,我们将其删除之后,再重新挂载设备(mount -t [type] [dev] [directory])即可。

通过分析,发现我们的情况,不符合以上几种常见的问题,所以只能自己找答案。

经过查询 inode 占用情况,以及跟正常磁盘的对比,发现该盘 du 和 df 的 inode 统计都是相同的,应该不存在多统计文件或少统计文件的情况,如图:

3b18975e55fb960961db606ffa922454.png

另,在进行 tune2fs -l /dev/sdc1 时,在参数底部,发现磁盘有错误,报错如下:

49f98297586128dec78ace72c6f96a8c.png

说明该磁盘在2019年的时候已经存在问题,当时刚好有过一次断电重启,估计就是那次重启,导致数据块损坏,空间无法释放。Last error function: ext4_wait_block_bitmap 也佐证了这一点,说明 block bitmap 里的内容无法读取。

具体分析可参考大神的文章:ext4块分配机制及源码分析

嗯,剩下的就是要修复磁盘了。

解决问题

  1. 首先就是停掉该 datanode 的业务,并下线节点,停止进程,备份数据……
  2. 使用 umount /dev/sdc1; 卸载硬盘;
  3. 使用 fsck -t ext4 /dev/sdc1; 进行磁盘修复,修复过程中可能会出现块无法读取,需要强制覆盖的提示,如下图: 6296bed35b78e.png 如果不想手动确认的话,可以使用 fsck -t ext4 /dev/sdc1 -y; 跳过提醒。
  4. 修复完成后,使用 mount /dev/sdc1 /data03; 重新挂载;
  5. 再次使用 tune2fs -l /dev/sdc1df 检查数据,发现空间使用正常,磁盘也没有报错了。 b53fca513cfc0ea44d26aeb60aad78be.png fb30f0c29610336a78174d1da0e57826.png
  6. 启动 datanode 进程,上线 datanode ,数据校验,未发现错误。

Done!

消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息