闢謠網傳的"刪除許多個本地文件,rsync 比 rm 快"

這是個人原創的我的心得,如有紕漏,多多指教
更多內容能夠訪問 個人博客

前言

公司有臺服務器產生太多臨時文件,同事在刪除文件的時候,說使用 rsync 會更快一些,使用 rm 可能會把機器搞掛,還引用網上一篇文章說 node

"rsync所作的系統調用不多:沒有針對單個文件作lstat和unlink操做。命令執行前期,rsync開啓了一片共享內存,經過mmap方式加載目錄信息。只作目錄同步,不須要針對單個文件作unlink"緩存

我對此抱有好奇與懷疑,在個人Linux知識中,從 Linux 中刪除文件,須要是文件的硬鏈接數n_link歸零、進程正在打開該文件的數n_count歸零,才能夠觸發文件系統對 inode 與對應磁盤塊的回收,實現刪除操做。這是金科玉言,完全刪除文件的系統調用必然用到 unlink 與 close。性能優化

對於網傳的理論,我在互聯網上仔細搜索,發現太多轉載的雷同的文章,卻沒有精華文章對上面的話作詳細的解釋。我決定本身研究下服務器

刪除大量文件的方法

網傳這樣的方法socket

例如刪除某目錄下一萬個以上小文件,使用 rm * -rf,既有操做上的風險,又耗時。性能

建議使用 rsync測試

mkdir /tmp/blank_dir
rsync --delete-before -a -H -v /tmp/blank_dir/ target_dir
  • 先創建空目錄,再同步空目錄到目標目錄
  • 注意以上命令中 blank_dir 後帶 /

rsync 選項說明:
--delete-before 接收者在傳輸以前進行刪除操做
--progress 在傳輸時顯示傳輸過程
--a 歸檔模式,表示以遞歸方式傳輸文件,並保持全部文件屬性
--H 保持硬鏈接的文件
--v 詳細輸出模式
--stats 給出某些文件的傳輸狀態優化

爲何刪除一萬個文件以上, rsync 比 rm 快

從根本入手,直接查看系統調用狀況,因而動手測試ui

實驗環境:Linux Arch 4.19code

建立必定數量的空白文件,分別使用 rm 與 rsync 刪除,並使用 strace -c 統計系統調用,須要額外注意的是 rsync 在本地使用了三個進程(generator, sender, receiver),因此須要 -f 選項告訴 strace 同時跟蹤全部fork和vfork出來的進程。(因爲 strace 輸出的信息太多,爲了閱讀體驗,打印詳情在附錄)

第一次,建立10個文件,分別刪除,查看統計輸出

查看 rm 的系統調用,耗時0.000000,總次數62

for i in $(seq 10); do touch tmp_$i;done 
strace -c rm * -rf

查看 rsync 的系統調用,總耗時0.008647,總次數365

for i in $(seq 10); do touch tmp_$i;done
strace -c -f rsync --delete -a -H ../blank_dir/ ./

由於10個文件的刪除,幾乎看不到時間,我第二次測試,刪除一萬個文件,結果:

rm 的系統調用,總耗時0.201209,總次數20063

rsync 的系統調用,總耗時0.625734,總次數20374

從這個結果來看,彷佛 rsync 比 rm 要慢,這裏有我使用 strace -f 統計 rsync 三個進程總耗時的緣由,改用使用 time 命令來計時,刪除一萬個文件以上,rsync 確實是比 rm 快上一些,那是由於我電腦cpu在三個以上,三個進程的rsync固然快一些

個人結論

網傳的 "刪除多個文件,rsync 比 rm 快" 的方法,我認爲不必定準確,理由以下:

  • 我電腦版本爲Linux Arch 4.19,測試中 rm 與 rsync 一樣使用了 mmap 的磁盤映射內存的性能優化操做,這個能夠在附錄中看到。
  • 不管是 rm 仍是 rsync,都使用了 unlink, unlink 的次數等同文件數量, 這與網傳的不符合。
  • 可能舊版本 Linux 的 rm 優化作的很差,對目錄的文件列表,缺乏優化的緩存處理
  • rm 命令通常是單進程的,而 rsync 有三個不一樣職責的進程(sender, receiver, generator),在多核機器上,rsync 執行效率更高,可是在單核機器可能表現比較低
  • 網傳的 rsync 刪除多文件的效率高是由於「目錄同步」,我多加搜索也沒有詳細說明,認爲這是誤傳。

我想,多是有人對 rsync 的評測不嚴謹,在本地刪除文件時,漏了檢查 rsync 的兩個進程的系統調用,才致使的以訛傳訛。

附錄

第一次,建立10個文件,分別刪除,查看統計輸出

使用 rm :

for i in $(seq 10); do touch tmp_$i;done 

strace -c rm * -rf
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         4           read
  0.00    0.000000           0         6           close
  0.00    0.000000           0         3           fstat
  0.00    0.000000           0         1           lstat
  0.00    0.000000           0         4         1 lseek
  0.00    0.000000           0         8           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1           ioctl
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2         1 arch_prctl
  0.00    0.000000           0         3           openat
  0.00    0.000000           0        10           newfstatat
  0.00    0.000000           0        10           unlinkat
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    62         3 total

使用 rsync, strace 的輸出中能夠看到 rsync fork 出兩個子進程

for i in $(seq 10); do touch tmp_$i;done       
strace -c -f rsync --delete -a -H ../blank_dir/ ./
strace: Process 17207 attached
strace: Process 17208 attached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 61.13    0.005286         587         9         5 wait4
  5.39    0.000466          46        10           unlink
  3.80    0.000329           9        34         1 select
  3.59    0.000310           8        37           mmap
  3.27    0.000283           5        51           read
  2.88    0.000249          62         4           getdents64
  2.68    0.000232          29         8           munmap
  2.43    0.000210           5        37           close
  2.36    0.000204           8        23         4 openat
  2.32    0.000201          10        19           write
  2.32    0.000201          14        14           lstat
  1.28    0.000111           5        19           fstat
  1.14    0.000099          12         8         8 connect
  0.83    0.000072           9         8           socket
  0.73    0.000063          31         2           utimensat
  0.67    0.000058           3        17           fcntl
  0.49    0.000042          14         3           socketpair
  0.45    0.000039           5         7           lseek
  0.40    0.000035          17         2         2 nanosleep
  0.38    0.000033           3        11           mprotect
  0.37    0.000032           2        12           rt_sigaction
  0.24    0.000021          10         2         1 stat
  0.23    0.000020          10         2         2 rt_sigreturn
  0.22    0.000019           9         2           chdir
  0.22    0.000019           9         2           getgroups
  0.15    0.000013           6         2           clone
  0.00    0.000000           0         6           brk
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         2           dup2
  0.00    0.000000           0         1           getpid
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           kill
  0.00    0.000000           0         1           getcwd
  0.00    0.000000           0         2           umask
  0.00    0.000000           0         1           geteuid
  0.00    0.000000           0         1           getegid
  0.00    0.000000           0         2         1 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.008647                   365        25 total

刪除 10 個文件,看起來 rsync 的系統調用次數比 rm 要多,我決定加大文件數量測試

第二次測試,刪除一萬個文件

for i in $(seq 10000); do touch tmp_$i;done  
strace -c rm * -rf                                
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 70.08    0.141015          14     10000           unlinkat
 29.67    0.059692           5     10000           newfstatat
  0.08    0.000158           6        24           brk
  0.04    0.000083          10         8           mmap
  0.02    0.000048          12         4           mprotect
  0.02    0.000036          12         3           openat
  0.02    0.000035           5         6           close
  0.01    0.000025           6         4           read
  0.01    0.000024          24         1           munmap
  0.01    0.000023           5         4         1 lseek
  0.01    0.000019           6         3           fstat
  0.01    0.000013           6         2         1 arch_prctl
  0.01    0.000011          11         1         1 access
  0.00    0.000010          10         1           execve
  0.00    0.000009           9         1           ioctl
  0.00    0.000008           8         1           lstat
------ ----------- ----------- --------- --------- ----------------
100.00    0.201209                 20063         3 total
strace -c -f rsync --delete -a -H ../blank_dir/ ./
strace: Process 16414 attached
strace: Process 16415 attached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 61.75    0.386408       42934         9         5 wait4
 19.18    0.120021          12     10000           unlink
 15.97    0.099912           9     10004           lstat
  2.21    0.013827        1063        13           getdents64
  0.14    0.000860          20        41           mmap
  0.12    0.000755          32        23         4 openat
  0.10    0.000604          11        54           read
  0.08    0.000479          12        37           close
  0.07    0.000422          35        12           munmap
  0.05    0.000338          30        11           mprotect
  0.05    0.000284          35         8         8 connect
  0.04    0.000251          13        19           fstat
  0.04    0.000239          19        12           rt_sigaction
  0.04    0.000236           5        40         1 select
  0.03    0.000192          24         8           socket
  0.03    0.000157           7        22           write
  0.02    0.000156          26         6           brk
  0.01    0.000084           4        17           fcntl
  0.01    0.000079          39         2           utimensat
  0.01    0.000078          11         7           lseek
  0.01    0.000060          20         3           socketpair
  0.01    0.000041          41         1           getcwd
  0.01    0.000036          18         2           umask
  0.00    0.000027          27         1           rt_sigprocmask
  0.00    0.000026          13         2           chdir
  0.00    0.000025          25         1         1 access
  0.00    0.000022          11         2         1 stat
  0.00    0.000022          22         1           geteuid
  0.00    0.000021          10         2         1 arch_prctl
  0.00    0.000020          20         1           execve
  0.00    0.000019          19         1           getegid
  0.00    0.000014           7         2         2 nanosleep
  0.00    0.000010           5         2           clone
  0.00    0.000009           4         2         2 rt_sigreturn
  0.00    0.000000           0         2           dup2
  0.00    0.000000           0         1           getpid
  0.00    0.000000           0         1           kill
  0.00    0.000000           0         2           getgroups
------ ----------- ----------- --------- --------- ----------------
100.00    0.625734                 20374        25 total
相關文章
相關標籤/搜索