Коли змінне середовище прискорює процес у 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 (а якщо ви не знаєте про файли двері (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 файлів, не дуже добре.

До речі, потрібний прапор --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-річної давності, ми спробували вимкнути перевірку атрибуту можливості:

$ 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:'

Це означає: не розфарбовуйте файли ні по атрубуту можливості, але за бітами 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.

Джерело: habr.com

Додати коментар або відгук