rsync 删除海量文件

由于业务侧使用时,一些脚本文件写的不够严谨,造成/var/spool/postfix/maildrop/目录经常被用户通知邮件文件堆满。而通过rm  -rf * 删除时,会提示-bash: /bin/rm: Argument list too long 。通过ls |xargs rm -rf 进行删除时也耗时较长,这里可以通过rsync进行删除。

 

一、rsync删除文件

针对上面的问题,我们可以通过以下方法清空该目录:

先创建一个空目录
mkdir /tmp/empty/
清空目标目录
# rsync --delete-before -avH --progress --stats /tmp/empty/ /var/spool/postfix/maildrop
rsync --delete -rlptD /tmp/empty/ /var/spool/postfix/maildrop/

 

选项说明:

-delete-before 接收者在传输之前进行删除操作
–progress 在传输时显示传输过程
-a 归档模式,表示以递归方式传输文件,并保持所有文件属性
-H 保持硬连接的文件
-v 详细输出模式
–stats 给出某些文件的传输状态

 

不过在使用上面的命令进行清理时,存在一个问题,清空后,目标目录的权限会和源目录的权限一样。如:/tmp/empty是root:root,而maildrop之前是postfix:postdrop ,执行之后也会maildrop目录的权限也会变成root:root 。由于-a权限是-rlptogD几个参数的集合,所以可以将og(owner:group)两个参数去掉。清空时自动保持之前的目录权限,如下:

rsync  --delete -rlptD /tmp/empty/ /var/spool/postfix/maildrop/

 

二、rsync与rm 删除速度比较

为什么rsync这么快呢?

rm删除内容时,将目录的每一个条目逐个删除(unlink),需要循环重复操作很多次;rsync删除内容时,建立好新的空目录,替换掉老目录,基本没开销。想要深层次的区分两个命令在调用系统函数时的区别,可以使用SystemTap工具进行分析。

创建了40万个文件,分别用rm和rsync进行删除操作,对syscall做统计。为了简化条件,这写文件全部是空文件(使用包含内容的文件对结果不会造成明显差异,有兴趣可以重试一下)。

统计syscall使用了dtruss工具,这是MacOSX上提供的syscall调试工具,基于DTrace。Linux上可以使用SystemTap来代替。

验证测试步骤

第一步,创建测试文件

# mkdir tmp/; seq 1 400000 | xargs -I{} touch tmp/file_{} 

创建的目录文件大小约为13M。这个大小指的是目录文件,不包含目录中文件,要注意。

第二步,使用dtruss执行rm命令测试

 

第三步,使用dtruss执行rsync命令测试

 

现象分析

  • rm
    • rm命令大量调用了lstat64和unlink,可以推测删除每个文件前都从文件系统中做过一次lstat操作。
    • lstat64的次数低于文件总数,还有另外的原因,之后会在另一篇文章中说明。
    • getdirentries64这个调用比较关键。
    • 过程:正式删除工作的第一阶段,需要通过getdirentries64调用,分批读取目录(每次大约为4K),在内存中建立rm的文件列表;第二阶段,lstat64确定所有文件的状态;第三阶段,通过unlink执行实际删除。这三个阶段都有比较多的系统调用和文件系统操作。
  • rsync
    • rsync所做的系统调用很少。
    • 没有针对单个文件做lstat和unlink操作。
    • 命令执行前期,rsync开启了一片共享内存,通过mmap方式加载目录信息。
    • 只做目录同步,不需要针对单个文件做unlink。

另外,在其他人的评测里,rm的上下文切换比较多,会造成System CPU占用较多——对于文件系统的操作,简单增加并发数并不总能提升操作速度。

总结

把文件系统的目录与书籍的目录做类比,rm删除内容时,将目录的每一个条目逐个删除(unlink),需要循环重复操作很多次;rsync删除内容时,建立好新的空目录,替换掉老目录,基本没开销。

结论:频繁做减法不如直接从头来过。

 

posted @ 2018-08-23 10:28  Star-Hitian  阅读(469)  评论(0)    收藏  举报