Linux du 和 df统计目录大小为何不一样?

简介: Linux du 和 df统计目录大小为何不一样?

1、问题


使用du 和df 分别对/etc 统计其大小,发现统计结果差距很大?何因?

[root@P1QW01 ~]# df -h /etc/
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/rootvg-rootlv
                      4.8G  249M  4.4G   6% /
[root@P1QW01 ~]# 
[root@P1QW01 ~]# du -sh /etc/
31M    /etc/
[root@P1QW01 ~]# 

--------------------update 2020年7月30日15:10:13------------------------------------------


最近发现目录空间不足的报警,查看一番发现df 统计的结果和du差距很大。

 home]# du -sh *
220K  ansibleDemo
28K cp.log
172M  gpadmin
4.0K  host.sh
36K ktabrm
36K ktahis
40K ktappt
36K ktauas
16K lost+found
1.4M  oracle
637M  scripts
home]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/root_vg-rootlv
                      9.8G  2.9G  6.4G  31% /
tmpfs                 127G  216K  127G   1% /dev/shm
/dev/sda2             477M   36M  416M   8% /boot
/dev/sda1             500M  272K  500M   1% /boot/efi
/dev/mapper/root_vg-homelv
                       20G   16G  2.8G  86% /home

2、结论


原因是:


df 统计的时候是从文件系统考虑的,不仅包含文件系统大小,还要统计被命令或者程序占用的空间,


例如 文件已经被删除,但是被某个进程持有。其原理是读取每个分区的superblock来获取空闲数据块、已使用数据块,从而计算出空闲空间和已使用空间,因此df统计的速度极快(superblock才占用1024字节)。所以非常快。

q1:为什么文件被删除了df -h 还可以统计的到?


要回答这个问题需要很多基础知识,以后有空再写两篇,这里简单说一下,只要bmap中不将这个文件的data block标记为未使用,就会算到实际使用的空间中。bmap是元数据区的一个位标记,其中记录的是数据区的block是否被使用。


du 是面向文件的,只计算文件或者目录占用空间,其具体做法就是stat 文件,然后统计其所占的实际物理空间,因此可以跨分区统计某些你想统计的文件大小总和。因为它们都能被stat找到并统计。

codis]# find / -type f -name "*.conf" -print0 | xargs -0 du -csh
8.0K  /datap11/gpseg0/pg_hba.conf
4.0K  /datap12/gpseg2/pg_hba.conf
12K total

如果文件被删除了,这种肯定是统计不到的。因此看到的du 统计的使用更少,而df 统计的结果更多,可能是因为文件被程序持有。

3、如何找出“丢失的空间”?


既然文件已经被删除了为何还不释放呢? 文件已经被删除,但是被某个进程持有。这种情况就不会释放。


如何查找出这些僵尸文件呢?

 regExp]# lsof |grep deleted

找到的结果就是一些文件已经被删除,但是空间还没有释放的。可以很久实际情况将持有的改文件的PID kill掉来释放空间。


可以使用如下命令批量删除。 生产环境谨慎操作。

for i in `lsof |grep deleted |awk '{ print $2 }'` ; do kill -15 $i ;done

至此,可以解决大多数问题,在网上找了很多都没有提到如果还是解决不了应该怎么办?


有的说是要重启服务器,这就.............


经过一番查询。发现 du -sh* 并不包括隐藏文件和目录。


果然  .ansible占了16GB,至此凶手找到了,ansible 的tmp文件删除就可以了。

.ansible]# du -sh *
16G tmp

再仔细看一下gp一个segment的录下的文件数量我惊呆了。40W+ 的文件目录数量,总共30GB,直接报错了。

ansible]# ls tmp/|wc -l
406278
.ansible]# time rm -rf ./tmp/*
-bash: /bin/rm: Argument list too long
real  0m7.728s
user  0m4.686s
sys 0m0.408s

如何解决呢?通过传参的方式解决

.ansible]# time find /home/.ansible/ -name  "a*"  | xargs rm -rf "a*"
real  33m10.841s
user  0m7.251s
sys 0m53.530s

有没有更快的办法呢?


经过查询可以使用rsync ,使用--delete-before, -d 后跟两个目录,前一个目录为一个空目录,后一个目录为需要删除的目录。


经过测试,时间大约节省了一半的时间。


rsync 的原理大致是: 接收端的rsync会先删除目标目录下已经存在,但源端目录不存在的文件。也就是"多则删之,少则补之"。


如果是"--delete-before",则在目标端rsync刚启动时,会比较源端和目标端,对本利来说,经过比较发现目标端的文件夹是空的,那就是说源端的那个目录/home/.ansible/tmp/需要全部删除,于是就开始删除了。

30G /home/.ansible/tmp
 tmp]# ll |wc -l
410049
 tmp]# time rsync --delete-before -d /home/.ansible/tmp_1/ /home/.ansible/tmp/
real  14m7.573s
user  0m6.763s
sys 1m6.309s
也可以使用另外一个参数差别不大。
ll |wc -l
410515
 tmp]# df -h /home/.ansible/;echo;du -sh /home/.ansible/
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/rootvg-homelv
                      201G   42G  149G  22% /home
30G /home/.ansible/
You have new mail in /var/spool/mail/root
 tmp]# ll |wc -l
410597
 tmp]# time rsync -a --delete  /home/.ansible/tmp_1/ /home/.ansible/tmp/
real  13m42.883s
user  0m6.075s
sys 1m4.439s

在这里想说的是,如果都是文件的话,删除速度更快一些。看如下几个例子。

 redis]# for i in $(seq 1 410000);do echo text >>$i.txt;done
 redis]# time rsync -a --delete /redis/tmp/ /redis/
real  0m46.074s
user  0m0.336s
sys 0m44.341s
使用python删除
import os
import timeit
def main():
    for pathname,dirnames,filenames in os.walk('/redis/tmp/'):
        for filename in filenames:
            file=os.path.join(pathname,filename)
            os.remove(file)
if __name__=='__main__':
 t=timeit.Timer('main()','from __main__ import main')
print t.timeit(1)
 tmp]# time python /home/scripts/delansbieltmp.py 
13.6427898407
real  0m13.663s
user  0m1.733s
sys 0m10.006s

结论: 如果删除大量小文件,速度还是很快,使用rsync 就可以解决,如果有多级目录,删除起来会比较慢。

4、du和df的原理


du -s命令通过将指定文件系统中所有的目录、符号链接和文件使用的块数累加得到该文件系统使用的总块数,因为是stat所以所有类型的 ”文件” 都可以统计的到;而df命令通过查看文件系统磁盘块分配图得出总块数与剩余块数。文件系统分配其中的一些磁盘块用来记录它自身的一些数据,如i节点,磁盘分布图,间接块,超级块等。这些数据对大多数用户级的程序来说是不可见的,通常称为Meta Data

du命令是用户级的程序,它不考虑Meta Data,而df命令则查看文件系统的磁盘分配图并考虑Meta Data。df命令获得真正的文件系统数据,而du命令只查看文件系统的部分情况。


相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
17天前
|
存储 Linux 编译器
cmake的单目录和多目录的使用(Linux和Windows)
本文介绍了在Windows和Linux平台上使用CMake构建单目录和多目录项目的步骤,包括如何配置CMakeLists.txt文件以及如何生成和使用可执行文件、库文件。
14 2
|
18天前
|
移动开发 Linux
Linux 文件与目录管理
Linux 文件与目录管理
17 3
|
29天前
|
Linux
深入理解Linux中的cp命令:文件与目录的复制利器
深入理解Linux中的cp命令:文件与目录的复制利器
|
1月前
|
Linux Shell
10-9|linux上统计文件中单词次数
10-9|linux上统计文件中单词次数
|
1月前
|
Linux Shell Python
9-7|salt代码在linux机子那个目录
9-7|salt代码在linux机子那个目录
|
1月前
|
数据可视化 Ubuntu Linux
8-14|如何查看linux目录下文件大小
8-14|如何查看linux目录下文件大小
|
5月前
|
Linux 虚拟化 Windows
linux之df命令 查看分区大小
linux之df命令 查看分区大小
71 1
|
5月前
|
Linux 应用服务中间件 Shell
Linux下使用df与du命令查看磁盘空间
Linux下使用df与du命令查看磁盘空间
235 0
|
Linux
Linux磁盘空间的利器:`df` 和 `du`命令
Linux磁盘空间的利器:`df` 和 `du`命令
139 0
Linux磁盘空间的利器:`df` 和 `du`命令
|
Linux
Linux 磁盘空间 df & du 命令详解
Linux 磁盘空间 df & du 命令详解
127 0