公司使用云厂商提供的共享存储,底层使用的是GlusterFS,众所周知GlusterFS在元数据性能和小文件性能的处理方面一直存在不足。
GlusterFS使用弹性哈希算法代替传统分布式文件系统中的集中或分布式元数据服务,这个是GlusterFS最核心的思想,从而获得了接近线性的高扩展性,同时也提高了系统性能和可靠性。这种算法的特点是,给定确定的文件名,查找和定位会非常快。但是,如果事先不知道文件名,要列出文件目录(ls或ls -l),性能就会大幅下降。
我将GlusterFS作为底层存储给K8S供给PV的时候,经常需要删除里面文件,一般的文件还好,但是里面放的有前端文件,大量的小文件,一个目录下,可能存在上千个js文件,这样在 rm -rf *
的时候,发现命令卡在那里,一直动不了。
研究了一下rm
命令的删除流程,发现确实涉及到了遍历操作:
1 | rm命令大量调用了lstat64和unlink,可以推测删除每个文件前都从文件系统中做过一次lstat操作。过程:正式删除工作的第一阶段,需要通过getdirentries64调用,分批读取目录(每次大约为4K),在内存中建立rm的文件列表;第二阶段,lstat64确定所有文件的状态;第三阶段,通过unlink执行实际删除。这三个阶段都有比较多的系统调用和文件系统操作。 |
好在有人提到了另一个命令rsync
1 | rsync没有针对单个文件做lstat和unlink操作。命令执行前期,rsync开启了一片共享内存,通过mmap方式加载目录信息。只做目录同步,不需要针对单个文件做unlink。简单来说,rsync删除内容时,建立好新的空目录,替换掉老目录,基本没开销。rsync实际上用的就是替换原理。 |
我想要删除一个含有大量小文件的目录(比如vweb)时,只需要先创建一个空目录empty
,然后执行下面的命令,快了不止一个数量级。
1 | rsync --delete-before -a -H -v --progress --stats empty/ vweb/ |