Jede Menge Dateien löschen

  • Thread starter Thread starter Deleted member 11691
  • Start date Start date
Ich hab diese rsync Variante eben mal ausprobiert und muss schon sagen, das grenzt an Masturbation. :p

Der strace zeigt auch warum: es sind wesentlich weniger Syscalls notwendig.
Grob skizierter Ablauf bei find+xargs+rm:
  • find holt sich alle Dateien aus dem Verzeichnis und holt sich die Informationen dazu (lstat, fstat)
  • find übergibt die Liste an xargs
  • xargs sucht sich bei jeder Iteration (Anzahl der Teilmenge an Dateien) den Pfad zu rm neu. (PATH Variable!)
  • rm startet lädt jedes Mal Libs & Co, macht aber ebenfalls nochmal einen lstat und fstat auf die zu löschenden Daten
  • rm löscht sie

Grob skizierter Ablauf bei rsync:
  • rsync indiziert das leere Quell-Verzeichnis (nicht viel zu tun, ausser ein lstat auf das Verzeichnis)
  • rsync indiziert das Ziel-Verzeichnis und macht lstat und fstats auf die zu löschenden Daten
  • rsync setzt ein unlink auf die Files ab

Die Aktionen die rsync durchführt sind in ihrer Anzahl wesentlich geringer als bei der find+xargs+rm Variante. Wenn es der Verzeichnisbaum hergibt, könnte man es auch noch weiter parallelisieren. Dann dürften da ziemlich gute Zeiten zu erreichen sein. ;)

Vorhin im Schnelltest 500.000 Dateien in unter 30 Sekunden gelöscht. Das gefällt mir. ;)
 
Gut, nochmal getestet, Hardware war ein HP N40L (8GB RAM, Software-RAID1 (4x SATA-II 2TB), FreeBSD 9.1-RELEASE 64Bit).
Zum Testzeitpunkt liefen keine Dienste ausser syslogd, crond, sshd und smartd und die Kiste erhielt zuvor einen Reboot.
Um das Ganze nicht so realitätsfremd, wie es der Blogger tat, zu testen, habe ich bewusst keine 0 Byte Files genommen.
Desweiteren habe ich auf Grund der strace-Beobachtungen von Firewire2002 noch ein wenig am find+xargs+rm getuned:
Code:
[root@devzero:~] # mkdir -p /tmp/test{0,1,2,3}
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c 'for i in `/usr/bin/seq 200000` ; do /bin/echo $i > /tmp/test1/$i.txt ; done'
real 358.62
user 68.88
sys 275.58
      6824  maximum resident set size
        77  average shared memory size
      1288  average unshared data size
       125  average unshared stack size
  15201464  page reclaims
         0  page faults
         0  swaps
      1493  block input operations
      2528  block output operations
         0  messages sent
         0  messages received
         0  signals received
    603121  voluntary context switches
    253215  involuntary context switches
[root@devzero:~] # /usr/bin/du -hs /tmp/test1
785M    /tmp/test1
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/bin/find /tmp/test1 -name \*.txt -maxdepth 1 -type f | /usr/bin/xargs -n5000 -P5 /bin/rm -f'
real 6.87
user 0.84
sys 9.86
     65828  maximum resident set size
        15  average shared memory size
       247  average unshared data size
       243  average unshared stack size
     20764  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
    500236  voluntary context switches
     93969  involuntary context switches
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c 'for i in `/usr/bin/seq 200000` ; do /bin/echo $i > /tmp/test2/$i.txt ; done'
real 356.64
user 67.91
sys 277.17
      6824  maximum resident set size
        76  average shared memory size
      1286  average unshared data size
       125  average unshared stack size
  15201464  page reclaims
         0  page faults
         0  swaps
        58  block input operations
      2573  block output operations
         0  messages sent
         0  messages received
         0  signals received
    604092  voluntary context switches
    300457  involuntary context switches
[root@devzero:~] # /usr/bin/du -hs /tmp/test2
785M    /tmp/test2
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/bin/find /tmp/test2 -type f -delete'
real 5.59
user 0.18
sys 5.35
     65824  maximum resident set size
        44  average shared memory size
      2009  average unshared data size
       128  average unshared stack size
     16252  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
        26  voluntary context switches
       949  involuntary context switches
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c 'for i in `/usr/bin/seq 200000` ; do /bin/echo $i > /tmp/test3/$i.txt ; done'
real 357.77
user 68.44
sys 277.69
      6824  maximum resident set size
        76  average shared memory size
      1284  average unshared data size
       125  average unshared stack size
  15201464  page reclaims
         0  page faults
         0  swaps
        34  block input operations
      2650  block output operations
         0  messages sent
         0  messages received
         0  signals received
    603827  voluntary context switches
    313518  involuntary context switches
[root@devzero:~] # /usr/bin/du -hs /tmp/test3
785M    /tmp/test3
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/local/bin/rsync -a -delete /tmp/test0 /tmp/test3'
real 0.06
user 0.00
sys 0.00
      2492  maximum resident set size
       752  average shared memory size
      5404  average unshared data size
       384  average unshared stack size
       442  page reclaims
         1  page faults
         0  swaps
         3  block input operations
         0  block output operations
        19  messages sent
        29  messages received
         3  signals received
        28  voluntary context switches
         3  involuntary context switches
[root@devzero:~] #
Fazit:
find+xargs+rm ist mit etwas Tuning akzeptabel schnell
find+delete ist etwas schneller als find+xargs+rm
rsync ist extrem schnell, aber auch fehlertolerant?
 
In welche Richtung von Fehlern denkst du denn da?

Klar bei der rsync Variante muss einem schon bewusst sein, dass man da schon sehr aufpassen muss, was man da "synct". Weil in der bisherigen "minimal" Version keine Einschränkungen existieren. Es wird also alles rekursiv vernichtet, was sich unterhalb des angegebenen Verzeichnisses befindet. Excludes für den rsync Befehl könnten helfen. Ordnerstruktur liese sich auch in dem Leeren Verzeichnis nachbauen.

Ansonsten: Entweder er löschts oder es treten Fehler beim löschen auf, dann löscht er es eben nicht. Der Löschvorgang an sich ist bei allen Methoden am Ende nur ein unlink Syscall. Nur das Verfahren drumherum ist unterschiedlich.
Falls das Dateisystem Fehler aufweisen sollte, dürften die Folgen eines finds+xargs+rm die gleichen sein wie bei einem rsync.
Das einzige was ich mir noch vorstellen könnte, wäre das man hinterher mehr Daten im Zielverzeichnis hat, als vorher. ;)
 
Ich denke da mehr an Leer- und Sonderzeichen in Dateinamen, oder auch Dotfiles.
Eigentlich müsste rsync bei Excludes auch mit stat/stat2 um sich werfen, so dass der Vorteil gegenüber den find-Varianten nicht mehr ganz so dramatisch sein sollte. Aber da kann ich mich auch täuschen, testen werde ich es nicht, da mir die find-Varianten völlig ausreichen, zumal rsync nicht zum Basissystem gehört.
 
Gerade festgestellt, dass ich im rsync-Aufruf einen Fehler hatte und er daher gar nicht löschte ;)
Hier also die richtigen Werte für rsync:
Code:
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/local/bin/rsync -a --delete /tmp/test0/ /tmp/test3/'
real 6.28
user 0.35
sys 5.66
     15904  maximum resident set size
       372  average shared memory size
      1677  average unshared data size
       128  average unshared stack size
      3803  page reclaims
         0  page faults
         0  swaps
         0  block input operations
       156  block output operations
        29  messages sent
        40  messages received
         3  signals received
       198  voluntary context switches
       864  involuntary context switches
[root@devzero:~] #
Somit ist rsync also doch nicht signifikant schneller als die find-Varianten.
Und rsyncs --delete funktioniert nur recursive, ist also für selektive Löschungen nicht geeignet.

Keine Ahnung wie der Blogger auf seine Unterschiede kommt (gleicher Fehler wie ich beim ersten Versuch?)...
 
OK, ich nehme meinen vorigen Post zurück :(
Je mehr Files, desto deutlicher der Unterschied:
Code:
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c 'for i in `/usr/bin/seq 750000` ; do /bin/echo $i > /tmp/test1/$i.txt && /bin/echo $i > /tmp/test2/$i.txt && /bin/echo $i > /tmp/test3/$i.txt ; done'
real 12564.92
user 812.19
sys 11588.80
     25464  maximum resident set size
       113  average shared memory size
      1710  average unshared data size
       127  average unshared stack size
 173321808  page reclaims
         0  page faults
         0  swaps
      5133  block input operations
     70492  block output operations
         0  messages sent
         0  messages received
         2  signals received
   6817217  voluntary context switches
   8766773  involuntary context switches
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/bin/find /tmp/test1 -name \*.txt -maxdepth 1 -type f | /usr/bin/xargs -n5000 -P5 /bin/rm -f'
real 3139.12
user 5.30
sys 3989.85
    242068  maximum resident set size
        12  average shared memory size
         8  average unshared data size
       255  average unshared stack size
     76777  page reclaims
         0  page faults
         0  swaps
         0  block input operations
       172  block output operations
         0  messages sent
         0  messages received
         0  signals received
   4447977  voluntary context switches
    636048  involuntary context switches
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/bin/find /tmp/test2 -name \*.txt -maxdepth 1 -type f -delete'
real 1162.00
user 3.26
sys 1147.26
    242068  maximum resident set size
        44  average shared memory size
      2004  average unshared data size
       128  average unshared stack size
     60226  page reclaims
         0  page faults
         0  swaps
         0  block input operations
         0  block output operations
         0  messages sent
         0  messages received
         0  signals received
       339  voluntary context switches
    107246  involuntary context switches
[root@devzero:~] # /usr/bin/time -l -h -p /bin/sh -c '/usr/local/bin/rsync -a --delete /tmp/test0/ /tmp/test3/'
real 45.95
user 1.70
sys 35.03
     50552  maximum resident set size
       372  average shared memory size
      1681  average unshared data size
       128  average unshared stack size
     13459  page reclaims
         4  page faults
         0  swaps
         2  block input operations
       533  block output operations
        17  messages sent
        26  messages received
         3  signals received
      7954  voluntary context switches
     80868  involuntary context switches
[root@devzero:~] #
Also ist rsync doch extrem schnell, zumindest wenn man ein Verzeichnis vollständig rekursiv leeren will.

Wenn das Anlegen der Files nicht so quälend langsam wäre, würde ich ja noch mehr testen...
 
Ja, aber die letzten Test hatte ich extra auf echter Hardware durchgeführt, um die Flaschenhälse einer VM zu umgehen und somit näher an Realworld-Setups zu sein.

Egal, fest steht, dass rsync je nach Hardware erst ab circa 250000-500000 Files spürbar schneller als die find-Varianten ist, dafür aber beim selektiven Löschen deutlich komplexere Optionen benötigt.

Ich persönlich werde daher bei find+xargs+rm bleiben und dies auch künftig als primäre Lösung empfehlen.
 
Bei welchem Dateisystem ist der Test überhaupt gemacht worden?

Bei solchen Tests versucht man eigentlich einen großen Wertbereich abzudecken. Von einer Datei bis x. Wie wir sehen kosten die Syscalls nur bei sehr vielen Aufrufen mehr Zeit. Das ganze könnte man noch schön in eine Tabelle packen und eine lustige Grafik daraus basteln wie man es von den Präsentationen gewohnt ist *scnr*
 
jemand noch Lust zu messen, wie lange das "einfache löschen" des kompletten Verzeichnisses benötigt?
 
Back
Top