[Перевод] Когда переменная среды ускоряет процесс в 40 раз
Сегодня мы хотим рассказать о некоторых последних апдейтах системы Sherlock [это высокопроизводительный кластер Стэнфордского университета — прим. пер.], которые значительно ускоряют листинг файлов в каталогах с большим количеством записей.
В отличие от обычных статей, это скорее инсайдерский отчёт о том, как происходит регулярная работа над Sherlock, чтобы поддерживать его в наилучшем виде для наших пользователей. Надеемся в будущем публиковать больше таких статей.
Всё началось с вопроса в техподдержку от пользователя. Он сообщил о проблеме, что выполнение ls
занимает несколько минут в каталоге c более 15 000 записей в $SCRATCH
[каталог для временных файлов — прим. пер.].
Тысячи файлов в одном каталоге обычно создают трудности для файловой системы и такое определённо не рекомендуется. Пользователь знал это и признал, что это нехорошо, но упомянул, что на его ноутбуке листинг выполняется в 1000 раз быстрее, чем в Sherlock. Конечно, это нас задело. Поэтому мы заглянули глубже.
Мы рассмотрели, что на самом деле делает 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()
.
Наверняка это можно оптимизировать.
Следуя советам бага 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
не определена или отсутствует только один из её элементов
, она по умолчанию использует встроенную базу данных и всё равно использует цвета. Поэтому, если вы хотите отключить раскраску для определённого типа файла, вам нужно переопределить её с помощью
или
в файле DIR_COLORS
.
После множества проб и ошибок мы сузили круг поиска до этого:
EXEC 00 SETUID 00 SETGID 00 CAPABILITY 00
что записывается как
LS_COLORS='ex=00:su=00:sg=00:ca=00:'
Это означает: не раскрашивай файлы ни по атрубуту capabilities, но по битам setuid/setgid
, ни по флагу исполняемости.
И если не делать ни одной из этих проверок, то вызовы 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
.