df
与du
命令都是运维人员常用的检测存储空间大小的命令,平时我们并不太关注这两个命令的差别,但是经常会遇到这样一种场景,使用df查看到空间使用率已经非常高了,但使用du命令排查时发现不存在占用空间大的文件, 两者间的结果不一致。
du与df
du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在的,没有被删除的。他计算的大小就是当前他认为存在的所有文件大小的累加和。
df,disk free,通过文件系统来快速获取空间大小的信息,当我们删除一个文件的时候,这个文件不是马上就在文件系统当中消失了,而是暂时消失了,当所有程序都不用时,才会根据OS的规则释放掉已经删除的文件, df记录的是通过文件系统获取到的文件的大小,他比du强的地方就是能够看到已经删除的文件,而且计算大小的时候,把这一部分的空间也加上了,更精确了。
因此,如果用户删除了一个正在运行的应用所打开的某个目录下的文件,则du命令返回的值显示出减去了该文件后的目录的大小。但df命令并不显示减去该文件后的大小。直到该运行的应用关闭了这个打开的文件,df返回的值才显示出减去了该文件后的文件系统的使用情况。
通过lsof工具我们可以直观的排查到具体的问题进程,以便解决:
模拟案例
分别创建一个500M和1000M大小的文件。
1 | dd if=/dev/zero of=500mFile bs=1M count=500 |
然后开两个终端分别使用tail命令查看。
1 | 终端1执行 |
再开启一个终端使用lsof命令查看这两个文件的状态。
1 | lsof |grep File |
这个时候我们使用rm命令来删除了这两个文件。
1 | rm -rf 1000mFile 500mFile |
可以看到du已经显示为0,df无任何变化。通过lsof再看下进程状态。(sort -nrk 7是进行大小排序)
1 | lsof |grep File |sort -nrk 7 |
这个deleted表示该已经删除了的文件,但是文件句柄未释放。
想要释放此句柄直接kill掉对应进程就好了。
1 | kill -9 10106 |
可以看到,df的已用容量对应减少了1.5G。
在日常的运维工作中,我们可以直接通过以下命令来快速定位未释放文件句柄的进程,从而进行解决。
1 | lsof |grep deleted |
建议
在日常运维过程中,如果我们需要删除比较大的文件 可以使用 > filename
,这种可以直接释放磁盘空间,使用 rm 如果有进程在访问文件,则有可能出现磁盘空间不释放的情况。