使用场景

  • du:用于查看文件路径的空间使用情况
  • df:用于查看盘的空间使用情况

原理

1.df工作原理

对待统计文件逐个调用fstat这个系统调用,获取文件大小。
它的数据是基于文件获取的,所以有很大的灵活性,不一定非要针对一个分区,可以跨越多个分区操作。
如果针对的目录中文件很多,du速度就会很慢了。

2.du工作原理

使用statfs这个系统调用,直接读取分区的超级块信息获取分区使用情况。
它的数据是基于分区元数据的,所以只能针对整个分区。
由于df直接读取超级块,所以运行速度不受文件多少影响。

3.区别

df通过文件系统来快速获取空间大小的信息,当我们删除一个文件的时候,这个文件不是马上就在文件系统当中消失了,而是暂时消失了,当所有程序都不用时,才会根据OS的规则释放掉已经删除的文件, df记录的是通过文件系统获取到的文件的大小,他比du强的地方就是能够看到已经删除的文件,而且计算大小的时候,把这一部分的空间也加上了,更精确了。

du -s命令通过将指定文件系统中所有的目录、符号链接和文件使用的块数累加得到该文件系统使用的总块数;

df命令通过查看文件系统磁盘块分配图得出总块数与剩余块数。文件系统分配其中的一些磁盘块用来记录它自身的一些数据,如i节点,磁盘分布图,间接块,超级块等。这些数据对大多数用户级的程序来说是不可见的,通常称为Meta Data。

du命令是用户级的程序,它不考虑Meta Data,而df命令则查看文件系统的磁盘分配图并考虑Meta Data。

df命令获得真正的文件系统数据,而du命令只查看文件系统的部分情况。

如果用户删除了一个正在运行的应用所打开的某个目录下的文件,则du命令返回的值显示出减去了该文件后的目录的大小。但df命令并不显示减去该文件后的大小。
直到该运行的应用关闭了这个打开的文件,df返回的值才显示出减去了该文件后的文件系统的使用情况。当文件系统也确定删除了该文件后,这时候du与df就一致了。

df和du显示的数据不一致的情况

数据不一致的情况:
用户删除了大量的文件后,du命令就不会在文件系统目录中统计这些文件。如果此时还在运行中的进程持有这个已经被删除的文件句柄,那么这个文件就不会真正在磁盘中被删除,分区超级块中的信息也就不会更改,df命令仍会统计这个被删除的文件。通过lsof命令查询处于deleted状态的文件,被删除的文件在系统中被标记为deleted。如果系统有大量deleted状态的文件,会导致du和df命令统计结果不一致。

建议:
1.根据lsof列出的进程号,终止相应进程或者重启相应的服务。也可以重启实例,重启实例系统会退出现有的进程,开机后重新加载过程中,会释放调用的deleted文件的句柄。
2.Linux系统磁盘分区有保留区的概念,会给root或指定用户预留5%或更大的空间,当使用到这块保留区的空间时,fdisk命令的计算将会是负数。ext文件系统(包括ext2、ext3、ext4)都会默认预留5%的磁盘空间,使用root用户维护系统或记录系统关键日志使用。
3.当用du -sh *命令来统计目录总容量时,如果该路径下包含隐藏文件,是不会包含在统计结果里的。
4.由于数据盘挂载前该路径下就存在文件,挂载后用du无法查询到原路径文件。

1.df比du大

第一种情况:
用户删除了大量的文件后,du命令就不会在文件系统目录中统计这些文件。如果此时还在运行中的进程持有这个已经被删除的文件句柄,那么这个文件就不会真正在磁盘中被删除,分区超级块中的信息也就不会更改,df命令仍会统计这个被删除的文件。 通过lsof命令查询处于deleted状态的文件,被删除的文件在系统中被标记为deleted。如果系统有大量deleted状态的文件,会导致du和df命令统计结果不一致。

解决方法:
1.用lsof命令列出被程序所打开的文件文件名,并筛选出被删除的文件:

lsof | grep deleted > deleted_file

2.将文件按从大到小排序:

sort -nr -k 7 deleted_file > deleted_file_sorted

打开deleted_file_sorted文件,从上往下依次找,就可以看到一些被删除但是没有释放的文件,以及占用这些文件的程序。

top之后若却看不到相关的进程,因为top看到的是当前用户和系统的一些活跃进程,那些僵尸进程可能就显示不出来了。
解决办法:是用top -u 用户名,仅查看本用户的进程,就可以看到了,然后kill掉进程,文件就被释放了。

第二种情况:
元数据Meta Data的存在:
du命令是用户级的程序,它不考虑元数据。
df命令则查看文件系统的磁盘分配图因此考虑了元数据,所以df的返回值可能会因此大于du。

文件系统分配其中的一些磁盘块用来记录它自身的一些数据,如i节点,磁盘分布图,间接块,超级块等。
这些数据对大多数用户级的程序来说是不可见的,通常称为Meta Data。

2.df比du小

场景:使用docker,kubernetes等云原生环境
现象:df看到的已使用空间比du看到的已使用空间小很多
原因:使用docker镜像的时候,其实底层overlay文件系统是层级复用的原理,所以真正使用的磁盘空间并不会重复叠加,但是du看到的是会叠加的,因为对overlay文件系统路径进行du的时候,显示的是带覆盖的完整的使用空间。

# df
luzejia@luzejia-virtual-machine:~$ df -h
文件系统        容量  已用  可用 已用% 挂载点
tmpfs           1.6G  2.1M  1.6G    1% /run
/dev/sda3       491G   16G  451G    4% /
tmpfs           7.8G     0  7.8G    0% /dev/shm
tmpfs           5.0M  4.0K  5.0M    1% /run/lock
/dev/sda2       512M  5.3M  507M    2% /boot/efi
tmpfs           1.6G  4.7M  1.6G    1% /run/user/1000
/dev/sr0        127M  127M     0  100% /media/luzejia/CDROM
/dev/sr1        3.5G  3.5G     0  100% /media/luzejia/Ubuntu 22.04 LTS amd64

# 启动一个容器
luzejia@luzejia-virtual-machine:~$ sudo docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED             STATUS             PORTS     NAMES
e107632809ca   ubuntu    "bash"    About an hour ago   Up About an hour             ubuntu-test

# 再df的时候,多显示了一个挂载目录,挂载到了overlay文件系统下
luzejia@luzejia-virtual-machine:~$ sudo df -h
文件系统        容量  已用  可用 已用% 挂载点
tmpfs           1.6G  2.2M  1.6G    1% /run
/dev/sda3       491G   16G  451G    4% /
tmpfs           7.8G     0  7.8G    0% /dev/shm
tmpfs           5.0M  4.0K  5.0M    1% /run/lock
/dev/sda2       512M  5.3M  507M    2% /boot/efi
tmpfs           1.6G  4.7M  1.6G    1% /run/user/1000
/dev/sr0        127M  127M     0  100% /media/luzejia/CDROM
/dev/sr1        3.5G  3.5G     0  100% /media/luzejia/Ubuntu 22.04 LTS amd64
overlay         491G   16G  451G    4% /var/lib/docker/overlay2/fa666512fdebeaf8d6fa3611f248dd1d04a3be086dd256168e61166d89b846f9/merged

# 此时你du看这个路径,发现有168M的大小,
luzejia@luzejia-virtual-machine:~$ sudo du -BM /var/lib/docker
168M	/var/lib/docker

然而实际对比启动容器前后,df是没有明显变化的,因为服用了盘上的镜像层,所以盘的使用空间没有明显变化,但是挂载的这个overlay文件系统下的路径,你用du去看,就会给你显示完整的占用空间,层之间虽然是复用,但是也会给你展示完整的占用空间。

查看docker真正占用的磁盘空间

luzejia@luzejia-virtual-machine:~$ sudo docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          1         1         77.82MB   0B (0%)
Containers      1         1         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B

查看容器修改了哪些文件

docker container diff containerId

du查看隐藏文件

执行du -ah命令即可在统计结果中包含隐藏文件。

为什么overlay文件系统路径用du看到的是完整的带覆盖的占用,而非实际使用

猜测:
容器如果不做修改那么不会有额外的磁盘空间使用,当你修改的时候,会将修改做在overlay的读写层,那么假设你有磁盘1G,每个容器使用100M,但是基于同一个镜像的容器空间是复用的,如果不做修改的话,那么此时你可以启动非常多个,然后实际显示的是100M多一点,也就是底本多一点元数据的空间,但是容器使用的是copy on write,当写的时候就复制一个新的来写,读的时候复用,那么当大家都需要写的时候,那么你此时磁盘空间可能就不够了,但是如果一开始就把复用的这些空间先占起来,那么就使得当大家都需要写的时候,也是有空间的,相当于预留的思路。

相同的设计:
Kuberntes中的request请求,当你request之后,资源就被你申请走了,此时哪怕你不用,也会给你预留,以防止大家都需要使用的时候,发生资源争抢。

posted on 2024-09-09 13:55  jiayou111  阅读(49)  评论(0编辑  收藏  举报