Când o variabilă de mediu accelerează procesul de 40 de ori

Astăzi dorim să vorbim despre câteva dintre cele mai recente actualizări ale sistemului Sherlock [un cluster de înaltă performanță al Universității Stanford - n. trad.], care accelerează semnificativ listarea fișierelor în directoare cu un număr mare de înregistrări.

Spre deosebire de articolele obișnuite, acesta este mai degrabă un raport intern despre cum se desfășoară munca constantă la Sherlock pentru a-l menține în cea mai bună formă pentru utilizatorii noștri. Sperăm să publicăm mai multe astfel de articole în viitor.

Listarea multor fișiere necesită timp

Totul a început cu o întrebare în suportul tehnic de la un utilizator. Acesta a raportat o problemă, că execuția ls dură câteva minute în directorul cu mai mult de 15.000 de înregistrări din $SCRATCH [director pentru fișiere temporare - n. trad.].

Mii de fișiere într-un singur director creează de obicei dificultăți pentru sistemul de fișiere și este cu siguranță nerecomandat. Utilizatorul știa acest lucru și a recunoscut că nu este bine, dar a menționat că pe laptopul său listarea se face de 1000 de ori mai repede decât în Sherlock. Desigur, asta ne-a deranjat. Așa că am săpat mai adânc.

Pentru că ls arată bine

Am analizat ce face de fapt ls când listează un director, și de ce procesul durează atât de mult. În majoritatea distribuțiilor moderne ls se execută implicit ca ls --color=auto, pentru că tuturor le plac culorile.

Dar culorile frumoase au un preț: pentru fiecare fișier ls trebuie să obțină informații despre tipul fișierului, permisiuni, mărci, atribute extinse și așa mai departe, pentru a alege culoarea corespunzătoare.

Una dintre soluțiile simple ale problemei este să dezactivăm complet culorile în ls, dar imaginați-vă indignarea utilizatorilor. Cu siguranță nu putem renunța la ieșirea colorată, nu suntem monștri.

Așa că am săpat mai adânc. ls înfățișează înregistrările prin variabila de mediu LS_COLORS, pe care o stabilește dircolors(1) pe baza fișierului de configurare dir_colors(5). Da, fișierul executabil citește fișierul de configurare pentru a crea variabila de mediu, pe care apoi o folosește ls (și dacă nu știți despre fișierele door (do), atunci dir_colors va funcționa, indiferent de situație).

Hai să ne uităm mai în detaliu

Pentru a determina care dintre schemele de colorare cauzează încetinirea, am creat un mediu experimental:

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # nu încercați asta acasă!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

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

12,7 secunde pentru 10 000 de fișiere, nu prea bine.

Apropo, ai nevoie de un flag --color=always: deși acesta se referă la ls --color=auto, dar ls detectează când nu este conectat la terminal (de exemplu, printr-un canal sau cu redirectarea ieșirii) și dezactivează colorarea, dacă este setat auto. Un tip deștept.

Deci ce durează atât de mult? Ne-am uitat cu ajutorul strace:

$ strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors 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 apeluri lstat(), 10 000 apeluri getxattr() (care toate eșuează, pentru că în mediu nostru nu există atributele pe care le caută ls), 10 000 apeluri capget().

Cu siguranță asta poate fi optimizat.

Atributul capabilities? Nu.

Urmați sfaturile un bug de acum 10 ani, am încercat să dezactivăm verificarea atributului capabilities:

$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:)
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors 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 total

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

Wow, accelerare până la 8 secunde! Ne-am scăpat de toate aceste apeluri costisitoare getxattr(), iar apelurile capget() de asemenea, au dispărut, grozav.

Dar încă mai rămân aceste apeluri enervante lstat(), deși…

Câte culori sunt necesare?

Așa că am analizat mai în detaliu LS_COLORS.

La început, am dezactivat pur și simplu această variabilă:

$ 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

Ceva!?! Tot 13 secunde?

Se pare că atunci când variabila de mediu LS_COLORS nu este definită sau lipseste doar unul dintre elementele sale =color:, aceasta utilizează implicit baza de date încorporată și totuși folosește culori. Așadar, dacă vrei să dezactivezi colorarea pentru un anumit tip de fișier, trebuie să o suprascrii cu =: sau 00 în fișierul DIR_COLORS.

După multe încercări și greșeli, am restrâns căutarea la următoarele:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

ce se scrie ca

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

Aceasta înseamnă: nu colora fișierele după atribut capabilities, dar după biți setuid/setgid, nici după semnul de execuție.

Accelerăm ls

Și dacă nu facem niciuna din aceste verificări, apelurile lstat() dispar și acum este cu totul altceva:

$ 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 total

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

0,3 secunde pentru o listă de 10 000 de fișiere, un record.

Configurăm Sherlock

De la 13 secunde cu setările implicite la 0,3 secunde cu o mică configurare LS_COLORS înseamnă o accelerare de 40 de ori datorită absenței setuid / setgid și fișierelor executabile colorate. Nu este o pierdere atât de mare.

Desigur, acum este configurat în Sherlock pentru fiecare utilizator.

Dar dacă doriți să readuceți colorarea, puteți pur și simplu să reveniți la setările implicite:

$ unset LS_COLORS

Dar atunci, la directoarele cu un număr mare de fișiere, asigurați-vă că pregătiți cafea, în timp ce funcționează. ls.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster