Wenn eine Umgebungsvariable den Prozess um das 40-fache beschleunigt

Heute möchten wir über einige der neuesten Updates des Sherlock-Systems [das ist ein leistungsstarker Cluster der Stanford-Universität – Anm. d. Übers.] berichten, die das Auflisten von Dateien in Verzeichnissen mit einer großen Anzahl von Einträgen erheblich beschleunigen.

Im Gegensatz zu gewöhnlichen Artikeln handelt es sich hierbei eher um einen Insiderbericht darüber, wie die regelmäßige Arbeit an Sherlock abläuft, um ihn in bestmöglichem Zustand für unsere Nutzer zu halten. Wir hoffen, in Zukunft mehr solcher Artikel zu veröffentlichen.

Das Auflisten vieler Dateien benötigt Zeit.

Alles begann mit einer Anfrage an den Support von einem Benutzer. Er berichtete über ein Problem, bei dem die Ausführung ls mehrere Minuten in einem Verzeichnis mit über 15.000 Einträgen in $SCRATCH [Verzeichnis für temporäre Dateien – Anm. d. Übers.].

Tausende von Dateien in einem Verzeichnis stellen in der Regel eine Herausforderung für das Dateisystem dar, und das ist definitiv nicht empfehlenswert. Der Benutzer wusste dies und erkannte, dass es nicht ideal ist, erwähnte jedoch, dass das Auflisten auf seinem Laptop 1000 Mal schneller erfolgt als in Sherlock. Natürlich hat uns das getroffen. Deshalb haben wir tiefer gegraben.

Weil ls hübsch aussieht.

Wir haben uns angesehen, was tatsächlich bei ls dem Auflisten eines Verzeichnisses passiert und warum der Prozess so viel Zeit in Anspruch nimmt. In den meisten modernen Distributionen ls wird standardmäßig als ls --color=autoausgeführt, denn jeder mag Farbe.

Aber schöne Farben haben ihren Preis: Für jede Datei ls muss Informationen über den Dateityp, die Berechtigungen, Flags, erweiterte Attribute und Ähnliches eingeholt werden, um die entsprechende Farbe auszuwählen.

Eine der einfachen Lösungen für das Problem besteht darin, die Farben in ls ganz abzuschalten, aber stellen Sie sich das Entsetzen der Nutzer vor. Farbenfrohe Ausgaben dürfen auf keinen Fall entzogen werden, wir sind keine Monster.

Deshalb haben wir tiefer gegraben. ls Färbt die Einträge über die Umgebungsvariable LS_COLORS, die von dircolors(1) basierend auf der Konfigurationsdatei dir_colors(5)gesetzt wird. Ja, die ausführbare Datei liest die Konfigurationsdatei, um die Umgebungsvariable zu erstellen, die dann von ls verwendet wird (und wenn Sie nichts über die Dateien wissen, door do), wird dir_colors in jedem Fall funktionieren.Kommen wir näher darauf zu sprechen.

Um herauszufinden, welches der Färbeschemata die Verlangsamung verursacht, haben wir eine experimentelle Umgebung geschaffen:

Um festzustellen, welches der Farbgebungsschemata die Verlangsamung verursacht, haben wir eine experimentelle Umgebung geschaffen:

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # Versuch das nicht zu Hause!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

real    0m12.758s
user    0m0.104s
sys     0m0.699s

12,7 Sekunden für 10 000 Dateien, nicht sehr gut.

Übrigens, es wird ein Flag benötigt --color=always: obwohl es sich umwandelt in ls --color=auto, aber ls er erkennt, wenn er nicht mit einem Terminal verbunden ist (zum Beispiel über eine Pipe oder bei der Umleitung der Ausgabe) und deaktiviert die Farbgebung, wenn autogesetzt ist. Ein schlauer Kerl.

Was dauert also so lange? Wir haben es mit strace:

$ strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% Zeit     Sekunden  Mikrosekunden/Aufruf     Aufrufe    Fehler  syscall
------ ----------- ----------- --------- --------- ----------------
 44.21    0.186617          19     10000           lstat
 42.60    0.179807          18     10000     10000 getxattr
 12.19    0.051438           5     10000           capget
  0.71    0.003002          38        80           getdents
  0.07    0.000305          10        30           mmap
  0.05    0.000217          12        18           mprotect
  0.03    0.000135          14        10           read
  0.03    0.000123          11        11           open
  0.02    0.000082           6        14           close
[...]

Wow: 10 000 Aufrufe lstat(), 10 000 Aufrufe getxattr() (die alle fehlschlagen, weil in unserer Umgebung keine Attribute vorhanden sind, nach denen ls sucht), 10 000 Aufrufe capget().

Das sollte sicher optimiert werden können.

Attribut capabilities? Nein.

Folgend den Ratschlägen eines 10 Jahre alten Bugs, haben wir versucht, die Attributprüfung zu deaktivieren Capabilities festzulegen:

$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:)
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% Zeit     Sekunden  Mikrosekunden/Aufruf     Aufrufe    Fehler  syscall
------ ----------- ----------- --------- --------- ----------------
 98.95    0.423443          42     10000           lstat
  0.78    0.003353          42        80           getdents
  0.04    0.000188          10        18           mprotect
  0.04    0.000181           6        30           mmap
  0.02    0.000085           9        10           read
  0.02    0.000084          28         3           mremap
  0.02    0.000077           7        11           open
  0.02    0.000066           5        14           close
[...]
------ ----------- ----------- --------- --------- ----------------
100.00    0.427920                 10221         6 insgesamt

real    0m8.160s
user    0m0.115s
sys     0m0.961s

Wow, Beschleunigung auf 8 Sekunden! Wir haben uns von all diesen teuren Aufrufen befreit getxattr(), und die Aufrufe capget() sind auch verschwunden, großartig.

Aber es gibt immer noch diese lästigen Aufrufe lstat(), obwohl…

Wie viele Farben werden benötigt?

Deshalb haben wir uns das genauer angesehen LS_COLORS.

Zuerst haben wir einfach diese Variable deaktiviert:

$ echo $LS_COLORS
rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
$ unset LS_COLORS
$ echo $LS_COLORS

$  time ls --color=always $SCRATCH/dont | wc -l
10000

real    0m13.037s
user    0m0.077s
sys     0m1.092s

Was!?! Immer noch 13 Sekunden?

Es stellt sich heraus, dass, wenn die Umgebungsvariable LS_COLORS nicht definiert ist oder nur eines ihrer Elemente fehlt =color:, sie standardmäßig die eingebaute Datenbank verwendet und trotzdem Farben verwendet. Daher, wenn Sie die Farbe für einen bestimmten Dateityp deaktivieren möchten, müssen Sie sie mit =: oder 00 in der Datei DIR_COLORS.

Nach vielen Versuchen und Irrtümern haben wir die Suche auf Folgendes eingegrenzt:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

was als

LS_COLORS='ex=00:su=00:sg=00:ca=00:'

das bedeutet: färbe Dateien nicht nach Attributen Capabilities festzulegen, sondern nach Bits setuid/setgid, auch nicht nach Ausführbarkeitsflag.

Wir beschleunigen ls

Und wenn keine dieser Prüfungen durchgeführt wird, verschwinden die Aufrufe, und es ist nun ganz anders: lstat() $ export LS_COLORS='ex=00:su=00:sg=00:ca=00:' $ time strace -c ls --color=always $SCRATCH/dont | wc -l 10000 % Zeit Sekunden Mikrosekunden/Aufruf Aufrufe Fehler syscall ------ ----------- ----------- --------- --------- ---------------- 63.02 0.002865 36 80 getdents 8.10 0.000368 12 30 mmap 5.72 0.000260 14 18 mprotect 3.72 0.000169 15 11 open 2.79 0.000127 13 10 read [...] ------ ----------- ----------- --------- --------- ---------------- 100.00 0.004546 221 6 totalreal 0m0.337s user 0m0.032s sys 0m0.029s

0,3 Sekunden für eine Liste von 10.000 Dateien, Rekord.

Konfigurieren wir Sherlock

Von 13 Sekunden mit den Standardeinstellungen auf 0,3 Sekunden mit einer kleinen Anpassung

bedeutet eine 40-fache Beschleunigung aufgrund des Fehlens LS_COLORS und gefärbten ausführbaren Dateien. Nicht so ein großer Verlust. setuid / setgid und die farbigen ausführbaren Dateien. Nicht so ein großer Verlust.

Natürlich ist das jetzt in Sherlock für jeden Benutzer eingestellt.

Wenn Sie die Farbcodierung jedoch zurückbringen möchten, können Sie einfach zu den Standardeinstellungen zurückkehren:

$ unset LS_COLORS

Aber bei Verzeichnissen mit vielen Dateien machen Sie besser eine Kaffeepause, während es läuft. ls.

Quelle: habr.com

60GB SSD 8Gb DDR4