Когато променливата среда ускорява процеса 40 пъти

Днес искаме да ви разкажем за някои от последните ъпдейти на системата Sherlock [това е високопроизводителен клъстер на Станфордския университет — бел. ред.], които значително ускоряват изброяването на файлове в каталози с голям брой записи.

В контекста на обикновените статии, това е по-скоро инсайдерски доклад за редовната работа по Sherlock, за да го поддържаме в оптимално състояние за нашите потребители. Надяваме се в бъдеще да публикуваме повече такива статии.

Изброяването на много файлове отнема време.

Всичко започна с въпрос до техническата поддръжка от потребител. Той съобщи за проблема, че изпълнението ls отнема няколко минути в каталог с повече от 15 000 записа в $SCRATCH [каталог за временни файлове — бел. ред.].

Хилядите файлове в един каталог обикновено създават затруднения за файловата система и определено не се препоръчва. Потребителят беше наясно с това и призна, че не е добре, но спомена, че на лаптопа му изброяването се извършва 1000 пъти по-бързо, отколкото в Sherlock. Разбира се, ни засегна. Затова копнахме по-дълбоко.

Защото ls изглежда красиво.

Ние разгледахме какво всъщност прави ls при изброяването на каталог и защо процесът отнема толкова много време. В повечето съвременни дистрибуции ls по подразбиране се изпълнява като ls --color=auto, защото всички харесват цветове.

Но красивите цветове имат своя цена: за всеки файл ls т трябва да получи информация за типа на файла, неговите разрешения, флаговете, разширените атрибути и т.н., за да избере подходящия цвят.

Едно от простите решения на проблема е изобщо да се изключи цветът в ls, но представете си недоволството на потребителите. Никак не е позволено да се взема цветния изход, не сме чудовища.

Затова копнахме по-дълбоко. ls раскрашва записките чрез променлива на средата LS_COLORS, която се задава от dircolors(1) на база на конфигурационния файл dir_colors(5).Да, изпълняемият файл чете конфигурационния файл, за да създаде променливата на средата, която след това използва ls (а ако не знаете за файловете door (do), то dir_colors ще реагира, независимо от всичко).

Нека разгледаме по-подробно

За да определим коя от схемите за оцветяване причинява забавяне, създадохме експериментална среда:

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # не опитвайте това вкъщи!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

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

12.7 секунди за 10 000 файла, не е много добре.

Между другото, нужен е флаг --color=always: макар и той да се преобразува в ls --color=auto, но ls разпознава, когато не е свързан с терминала (например, по канал или с пренасочване на изхода) и отключва оцветяването, ако е зададена стойност auto. Умен човек.

Какво тогава отнема толкова време? Разгледахме с помощта на strace:

$ strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% време     секунди  микросекунди/извикване     извиквания    грешки системен повик
------ ----------- ----------- --------- --------- ----------------
 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
[...]

Невероятно: 10 000 извиквания lstat(), 10 000 извиквания getxattr() (които всички се провалят, защото в нашата среда няма атрибути, които tърси ls), 10 000 извиквания capget().

Сигурно може да се оптимизира.

Атрибут capabilities? Не.

Следвайки съветите на буг на 10 години, опитахме да деактивираме проверката на атрибута capabilities:

$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:)
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% време     секунди  микросекунди/извикване     извиквания    грешки системен повик
------ ----------- ----------- --------- --------- ----------------
 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 общо

реално    0m8.160s
потребител    0m0.115s
система    0m0.961s

Уау, ускорение до 8 секунди! Премахнахме всички тези скъпи извиквания getxattr(), и извикванията capget() също изчезнаха, чудесно.

Но все пак останаха тези досадни извиквания lstat(), макар и…

Колко цвята са нужни?

Затова разгледахме по-подробно LS_COLORS.

Първо просто деактивирахме тази променлива:

$ 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

Какво!?! Все още 13 секунди?

Оказва се, че когато променливата на средата LS_COLORS не е определена или липсва само един от елементите й =color:, по подразбиране използва вградена база данни и все пак използва цветове. Затова, ако искате да изключите оцветяването за определен тип файл, трябва да я преопределите с =: или 00 в файла DIR_COLORS.

След множество проби и грешки стеснихме търсенето до следното:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

което се записва като

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

Това означава: не оцветявай файловете нито по атрибута capabilities, нито по битовете setuid/setgid, нито по флага за изпълнимост.

Ускоряване ls

И ако не се извършват нито едни от тези проверки, повикванията lstat() изчезват, и сега става съвсем различно:

$ 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 секунди за списък от 10 000 файла, рекорд.

Настройваме Шерлок

От 13 секунди с настройки по подразбиране до 0,3 секунди с малка настройка LS_COLORS означава 40-кратно ускорение за сметка на отсъствието на setuid / setgid и оцветени изпълними файлове. Не толкова голяма загуба.

Разбира се, сега това е настроено в Sherlock за всеки потребител.

Но ако искате да възвърнете оцветяването, можете просто да се върнете към настройките по подразбиране:

$ unset LS_COLORS

Но тогава, когато имате директории с голям брой файлове, не забравяйте да си направите кафе, докато работи. ls.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster