Когда переменная среды ускоряет процесс в 40 раз

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Сегодня мы хотим рассказать о некоторых последних апдейтах системы Sherlock [это высокопроизводительный кластер Стэнфордского университета — прим. пер.], которые значительно ускоряют листинг файлов в каталогах с большим количеством записей.

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

Листинг многих файлов занимает время


Всё началось с вопроса в техподдержку от пользователя. Он сообщил о проблеме, что выполнение ls занимает несколько минут в каталоге c более 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} # don't try this at home!
$ 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
% 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
[...]

Ничего себе: 10 000 вызовов lstat(), 10 000 вызовов getxattr() (которые все терпят неудачу, потому что в нашей среде нет атрибутов, которые ищет 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
% 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

Ух ты, ускорение до 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;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

Что!?! По-прежнему 13 секунд?

Оказывается, когда переменная среды LS_COLORS не определена или отсутствует только один из её элементов <type>=color:, она по умолчанию использует встроенную базу данных и всё равно использует цвета. Поэтому, если вы хотите отключить раскраску для определённого типа файла, вам нужно переопределить её с помощью <type>=: или <type> 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 файлов, рекорд.

Настраиваем Sherlock


От 13 секунд с настройками по умолчанию до 0,3 секунды с небольшой настройкой LS_COLORS означает 40-кратное ускорение за счёт отсутствия setuid / setgid и раскрашенных исполняемых файлов. Не такая большая потеря.

Конечно, теперь это настроено в Sherlock для каждого пользователя.

Но если вы хотите вернуть раскраску, то можете просто вернуться к настройкам по умолчанию:

$ unset LS_COLORS

Но тогда на каталогах с большим количеством файлов обязательно заваривайте кофе, пока работает ls.
Источник: https://habr.com/ru/post/450806/


Интересные статьи

Интересные статьи

17 ноября Apple официально представила устройства на базе своего нового ARM-процессора Apple M1. Естественно, это событие не могло быть не замечено со...
В приложениях Lingualeo сложился довольно редкий кейс. Их создали до того, как появились кроссплатформенные технологии, но через несколько лет туда добавили модули на React Native. К...
Здесь на хабре много различных инструкций по использованию Django. Эти инструкции часто включают много кода и представляют последовательность шагов, которые нужно сделать, чтобы созда...
COVID-19, уже называется «пандемией века». Но это так же может быть и самое масштабное «фиаско века». Читать дальше →
Если в вашей компании хотя бы два сотрудника, отвечающих за работу со сделками в Битрикс24, рано или поздно возникает вопрос распределения лидов между ними.