聊聊删文件的那些破事
- 前言
- 正文
- rm命令
- find命令
- perl方式
- 10w文件删除对比
- 50w文件删除对比
- 100w文件删除对比
- 结语
前言
在操作系统的日常运维中,我们经常会做文件的创建、删除、修改操作,尤其是删除,无论是定期清理日志文件,还是做完一个操作以后删除临时文件,这都是非常常见的操作,如果你运维的服务器是非常小型的,而且业务量并不多,那也许你永远不会遇到在文件删除时产生的性能问题;但是如果你需要运维临时文件产生巨多或者日志产生巨多或者其他会产生大量文件的服务器,你也许会遇到删除文件时的瓶颈问题,其中最常见的就是/bin/rm: Argument list too long
;如果还没有遇到,可以随便找一个目录,创建一个测试文件夹,并生成随机的文件,然后尝试rm所有文件:
mkdir file_test
cd file_test
for i in $(seq 1 500000); do echo testing >> $i.txt; done
rm -rf *
相信很快你就会遇到上述的问题,从这个问题出发,我们聊聊删除文件的这些破事。
正文
在Linux中,虽然不同的文件系统在数据删除上的具体实现有所不同,但均是对inode进行操作,更改文件的元数据信息,就和HDFS一样,你能否找到数据取决于NameNode里有没有存对应块的元数据信息。
找到几个博文解释ext各文件系统的数据删除原理,放在这里,感兴趣可以看看:
ext4文件系统文件删除解析
ext2和ext3文件系统文件删除解析
rm命令
rm命令虽然是最常用的用来删除文件的命令,但是正如我上文所说,当文件数过多的时候就会无法执行,这种情况下,常见的方式是通过一些关键字做文件的筛选删除,尽量保证每批删除的文件数量在rm允许的范围内,比如按照文件所带的日期或者按照字母开头来筛选:
rm -rf *20220921*
rm -rf a*
当然,在报错/bin/rm: Argument list too long
的时候,删除操作是没有进行的,所以无论执行多少次,文件都没被删除。
find命令
当通过一些关键字做筛选无法满足我们的运维要求时,就要寻求别的方式了,比如文件名没有明显的特征,或者需要按照文件的生成日期进行删除等场景,大部分人会使用类似以下的命令进行删除:
find $path -mtime +3 -name "*" -type f -exec rm -rf {} \;
原先我也使用这个命令去做文件删除,但是耗时非常久,这是因为find结合rm -rf命令的原理是对于所有搜索出来满足条件的文件,都执行一次rm -rf命令。
一个更好的替代方式是以下的命令格式:
find $path -mtime +3 -name "*" -type f -delete
以下是两种方式删除相似体量的文件耗时的对比:
能够看出来明显的区别,所以下次再使用find删除文件的时候还是尽量使用delete,性能能够提升很多;
当然,如果你能用rm来实现的时候,还是用rm会好一些:
perl方式
除了上述两种方式,还有一种使用很少的方式,那就是用perl脚本来做文件删除,从我的测试来看,之所以知道这个也是因为之前看到网上的大佬说perl的性能比find delete还要高,但是在我的测试下并不是这样,性能最好的还是find delete,以下是删除10w个文件和50w个文件的性能对比:
10w文件删除对比
perl方式
find delete方式
50w文件删除对比
perl方式
find delete方式
100w文件删除对比
perl方式
find delete方式
当然了,在进行筛选的情况下我没有实际做过测试,我估计在极大数据量的情况下,性能差距不会太大的,如果有朋友有兴趣测试可以继续下去,并给我留言,附上我的清理脚本,这个脚本会在给定目录下再遍历一层进行数据删除:
#!/usr/bin/perluse File::Find;
use File::Spec;my $path="/home/test";opendir DH, $path or die "cannot chdir to $path : $!";for my $p (readdir DH) {next if $file eq "." or $file eq "..";my $sonpath=File::Spec->catdir($path,$p);opendir SH, $sonpath or die "cannot chdir to $sonpath : $!";for my $file (readdir SH) {next if $file eq "." or $file eq "..";next if $file =~ /^\./;my $abspath=File::Spec->catdir($sonpath,$file);my @s=stat("$abspath");if ((time()-$s[8]) > (60*60*24*2)){print "delete file $abspath\n";unlink $abspath;}}closedir SH;
}
closedir DH;
结语
一直以来都只是简单的使用rm命令做数据删除,这次因为业务上的需要,参与到大量文件的清理工作中,想要找到在linux下最高效的数据清理方式,也正是在这些目标的驱动下,了解到更多的文件清理方法,希望在以后的不断学习中能够探索到更高效的方法。