Kiedy zmienna środowiskowa przyspiesza proces 40 razy

Dziś chcemy opowiedzieć o niektórych ostatnich aktualizacjach systemu Sherlock [to wysokowydajny klaster Uniwersytetu Stanforda — przyp. tłum.] , które znacznie przyspieszają listing plików w katalogach z dużą ilością wpisów.

W przeciwieństwie do zwykłych artykułów, jest to raczej raport insidera na temat regularnej pracy nad Sherlockiem, aby utrzymać go w jak najlepszej formie dla naszych użytkowników. Mamy nadzieję w przyszłości publikować więcej takich artykułów.

Listing wielu plików zajmuje czas

Wszystko zaczęło się od pytania w pomocy technicznej od użytkownika. Zgłosił problem, że wykonanie ls zajmuje kilka minut w katalogu z ponad 15 000 wpisów w $SCRATCH [katalog na pliki tymczasowe — przyp. tłum.].

Tysiące plików w jednym katalogu zazwyczaj stwarzają trudności dla systemu plików i zdecydowanie nie jest to zalecane. Użytkownik o tym wiedział i przyznał, że to nie jest dobre, ale wspomniał, że na jego laptopie listing wykonuje się 1000 razy szybciej niż w Sherlocku. Oczywiście, dotknęło nas to. Dlatego zaglądnęliśmy głębiej.

Bo ls wygląda ładnie

Zbadaliśmy, co tak naprawdę robi ls podczas listowania katalogu i dlaczego proces zajmuje tyle czasu. W większości nowoczesnych dystrybucji ls domyślnie działa jako ls --color=auto, ponieważ wszyscy lubią kolor.

Ale ładne kolory mają swoją cenę: dla każdego pliku ls musi uzyskać informacje o typie pliku, jego uprawnieniach, flagach, rozszerzonych atrybutach i tym podobnych, aby wybrać odpowiedni kolor.

Jednym z prostych rozwiązań problemu jest całkowite wyłączenie koloru w ls, ale wyobraź sobie oburzenie użytkowników. Absolutnie nie można zabrać kolorowego wyjścia, nie jesteśmy potworami.

Dlatego zajrzeliśmy głębiej. ls koloruje wpisy za pomocą zmiennej środowiskowej LS_COLORS, która jest ustawiana przez dircolors(1) na podstawie pliku konfiguracyjnego dir_colors(5). Tak,plik wykonywalny odczytuje plik konfiguracyjny w celu utworzenia zmiennej środowiskowej, którą później wykorzystuje ls (a jeśli nie wiesz o plikach door (do), to dir_colors , nieważne co.) zadziałaZbadajmy to bliżej

Aby określić, która z schematów kolorów powoduje spowolnienie, stworzyliśmy środowisko eksperymentalne:

$ mkdir $SCRATCH/dont $ touch $SCRATCH/dont/{1..10000} # nie próbuj tego w domu! $ time ls --color=always $SCRATCH/dont | wc -l 10000real 0m12.758s user 0m0.104s sys 0m0.699s

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # nie próbuj tego w domu!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

czas rzeczywisty    0m12.758s
czas użytkownika    0m0.104s
czas systemowy     0m0.699s

12,7 sekundy dla 10 000 plików, niezbyt dobrze.

A propos, potrzebna flaga --color=always: choć odwołuje się w ls --color=auto, ale ls rozpoznaje, kiedy nie jest podłączony do terminala (np. przez kanał lub z przekierowaniem wyjścia) i wyłącza kolorowanie, jeśli ustawiona jest wartość auto. Mądry facet.

Co więc zajmuje tyle czasu? Sprawdziliśmy przy użyciu strace:

$ strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% czas     sekundy  usecs/call     wywołania    błędy 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
[...]

O rany: 10 000 wywołań lstat(), 10 000 wywołań getxattr() (które wszystkie kończą się niepowodzeniem, ponieważ w naszym środowisku nie ma atrybutów, których szuka ls), 10 000 wywołań capget().

Na pewno można to zoptymalizować.

Atrybut capabilities? Nie.

Podążając za radami błędu sprzed 10 lat, próbowaliśmy wyłączyć sprawdzanie atrybutu zdolnościami:

$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:)
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% czas     sekundy  usecs/call     wywołania    błędy 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 łącznie

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

Wow, przyspieszenie do 8 sekund! Pozbyliśmy się wszystkich tych kosztownych wywołań getxattr(), a wywołania capget() też zniknęły, świetnie.

Ale wciąż zostały te uciążliwe wywołania lstat(), chociaż…

Ile potrzebnych jest kolorów?

Dlatego przyjrzeliśmy się temu dokładniej LS_COLORS.

Na początku po prostu wyłączyliśmy tę zmienną:

$ 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;
$ unset LS_COLORS
$ echo $LS_COLORS

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

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

Co!?! Nadal 13 sekund?

Okazuje się, że kiedy zmienna środowiskowa LS_COLORS nie jest zdefiniowana lub brakuje tylko jednego z jej elementów =color:, domyślnie korzysta z wbudowanej bazy danych i wciąż używa kolorów. Dlatego, jeśli chcesz wyłączyć kolorowanie dla danego typu pliku, musisz ją nadpisać za pomocą = lub 00 w pliku DIR_COLORS.

Po wielu próbach i błędach zawęziliśmy poszukiwania do tego:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

co jest zapisane jako

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

To oznacza: nie koloruj plików ani według atrybutu zdolnościami, ani według bitów setuid/setgid, ani według flaga wykonywalności.

Przyspieszamy ls

A jeśli nie wykonasz żadnego z tych sprawdzeń, to wywołania lstat() znikają, a teraz jest zupełnie inaczej:

$ export LS_COLORS='ex=00:su=00:sg=00:ca=00:'
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors 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 razem

real    0m0.337s
user    0m0.032s
sys     0m0.029s

0,3 sekundy na liście 10 000 plików, rekord.

Konfigurujemy Sherlocka

Od 13 sekund z ustawieniami domyślnymi do 0,3 sekundy z niewielką konfiguracją LS_COLORS oznacza 40-krotne przyspieszenie dzięki braku setuid / setgid i kolorowanych plików wykonywalnych. Nie taka wielka strata.

Oczywiście, teraz jest to skonfigurowane w Sherlock dla każdego użytkownika.

Ale jeśli chcesz przywrócić kolorowanie, możesz po prostu wrócić do ustawień domyślnych:

$ unset LS_COLORS

Ale wtedy na katalogach z dużą ilością plików koniecznie parz kawę, podczas gdy to działa. ls.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster