对集群上 df 和 du 命令显示结果不一致的排查记录
目录
- 1 对集群上 df 和 du 命令显示结果不一致的排查记录
- 1.1 背景
- 1.2 猜想
- 1.2.1 不会是把文件系统弄坏了吧!
- 1.2.2 有些人的小文件太多,把 inode 给用光了!
- 1.2.3 有一些邪恶文件藏在了黑暗角落里!
- 1.3 破案
- 1.4 结局
对集群上 df 和 du 命令显示结果不一致的排查记录
背景
在集群上跑作业,然后把磁盘空间吃掉了。把占用空间很大的文件删掉后,du /home
命令的结果显示磁盘占用已经回到了正常水平,但是 df -h
显示,/home
所在分区的磁盘占用率还是 100%,也不能新建和修改文件。
猜想
不会是把文件系统弄坏了吧!
仔细想了想好像不可能,因为平时都是用普通用户的身份工作的……不太可能搞出影响文件系统的操作。
有些人的小文件太多,把 inode 给用光了!
看起来有可能,但是回想下很久很久以前自己做赛博仓鼠的时候遇到的问题,就会发现两个问题表现完全不一样。
很久很久以前,赛博鼠鼠 jyi 试图往自己的鼠鼠洞里塞图片,发现没有磁盘空间了!他 df
了下,发现硬盘空间还有很多,但是新建文件就是会出错。他又试了试往已有的文件后面追加写入一些东西,好像可以成功。他觉得非常奇怪,“凭什么磁盘有空间,但是就是不让我放东西呢?”
用一种比较笨蛋的方法来看 ext{2,3,4}
文件系统,就知道文件系统中,一个文件需要 1 个 inode 和许多许多 block。其中,inode 用来存放文件的元数据,block 用来存放文件本身。由于 block 数量一般多于 inode 的数量(block 的数量少于 inode 的数量有啥用啊……),所以可能会出现 inode 耗尽,而 block 有剩余的情况。在这种情况下,无法新建文件,却可以修改文件。
因为赛博鼠鼠 jyi 非常菜,所以他与电脑搏斗了一番后才想起关于 inode 的知识。他 df -i
了一下,发现自己要存放图片的文件系统的 inode 已经用光了。最后他把一些图片打包成 sfs,再挂载到世界树目录树上,从而在原本的文件系统里回收了一些 inode,终于解决了这个问题。
回到集群上来,为什么这个表现和集群上遇到的状况完全不一样呢?因为经过检查发现,集群上显示 df -i
不是 100%,df -h
显示的使用率是 100%;而很久很久以前和自己的电脑搏斗时,df -i
显示的使用率是 100%,df -h
则是比 100 小不少的数字。
这说明集群上很可能不是很多小文件把 inode 用光的问题,更可能是巨大文件很简单地把 block 用光的问题。
有一些邪恶文件藏在了黑暗角落里!
Linux 下面是可以往非空目录上挂载文件系统的,挂载后原目录里有的文件将会被遮盖掉。这些文件显然会被 df
统计,但是不会被 du
统计。
显然,最简单的方法就是把根目录之外的所有目录卸载,然后跑一下 df
和 du
。然而,现在要操作的是运行中的系统(也许还有同学在上面跑神秘程序,那种中断了会遭遇线下真人快打的),不能这么粗暴地处理……
最后我找了个 tmpfs /run/mnt
(因为根目录下没法新建文件夹做挂载点了),然后 mount --bind / /run/mnt
。接着进 /run/mnt
一看,发现 df
和 du
的结果仍然不同!仍然是 du
很少一点,df
巨大无比的结果。
破案
正在自闭时,突然想起来,好像学文件系统时在懵懵懂懂的时候学到了 Linux 下 inode 结构体里,有关 i_count
和 i_nlink
的知识。其中,i_count
代表当前有多少个文件描述符引用了这个文件,i_nlink
代表这个文件在文件系统里有多少个硬链接。当且仅当 i_count
和 i_nlink
都为零时,这个 inode 和她所持有的 block 才被会释放。有没有这种可能,一个神秘邪恶,吃光了磁盘的巨大文件,它的 i_nlink
是 0 同时 i_count
非零,这样它不会被递归查看文件名的 du
找到,但是能被统计 block 的 df
给检查到呢?
于是使用 lsof | grep deleted
一查,果然有一堆坏比 Perl 程序,打开了巨大文件没关。文件的所有者是我,大小有 780G。考虑到集群上好像只有我写 Perl,所以主谋是谁应该不言自明了……
结局
使用天火圣裁发动了一次牛逼的攻击……其实是 ps -u jyi
,把自己所有的进程,不管好比还是坏比都干掉了。然后 df
了几次,看着可用空间逐渐上涨。
问题最终解决了,可喜可贺可喜可贺。另外给好朋友说这个事时,还听说在 “进程打开了文件,但是文件不小心删掉了” 这种情况下,在进程关闭之前,可以去 /proc/X/fd/Y
下面把文件找回来。其中 X
是进程 pid,Y
是软链接,名字就是文件描述符,目标是被打开的文件,用 cat
命令就可以把文件给找回来。利用的也是 inode 释放的机制。
总之,Linux 真神奇啊 :3