Quando uma variável de ambiente acelera o processo em 40 vezes

Hoje queremos falar sobre algumas das atualizações mais recentes do sistema Sherlock [um cluster de alto desempenho da Universidade de Stanford — nota do tradutor], que aceleram significativamente o listagem de arquivos em diretórios com um grande número de registros.

Ao contrário de artigos comuns, este é mais um relatório interno sobre como o trabalho regular no Sherlock é realizado para mantê-lo em excelente forma para nossos usuários. Esperamos publicar mais artigos como este no futuro.

Listar muitos arquivos leva tempo.

Tudo começou com uma pergunta para o suporte técnico de um usuário. Ele relatou um problema em que a execução ls levava vários minutos em um diretório com mais de 15.000 registros em $SCRATCH [diretório para arquivos temporários — nota do tradutor].

Milhares de arquivos em um único diretório geralmente criam dificuldades para o sistema de arquivos, e isso definitivamente não é recomendado. O usuário sabia disso e reconheceu que não era bom, mas mencionou que em seu laptop a listagem era 1000 vezes mais rápida do que no Sherlock. Claro, isso nos incomodou. Portanto, fomos mais a fundo.

Porque o ls parece bonito.

Analisamos o que o ls realmente faz ao listar um diretório e por que o processo leva tanto tempo. Na maioria das distribuições modernas, ls é executado por padrão como ls --color=auto, porque todos gostam de cores.

Mas cores bonitas têm seu preço: para cada arquivo ls é necessário obter informações sobre o tipo de arquivo, suas permissões, flags, atributos estendidos e assim por diante, para escolher a cor apropriada.

Uma das soluções simples para o problema é desabilitar a cor no ls, mas imagine a indignação dos usuários. De forma alguma vamos retirar a saída colorida, não somos monstros.

Por isso, fomos mais a fundo. ls colore as entradas através da variável de ambiente LS_COLORS, que é definida por dircolors(1) com base no arquivo de configuração dir_colors(5).Sim, o executável lê o arquivo de configuração para criar a variável de ambiente, que depois é usada pelo ls e se você não sabe sobre arquivos door (do), então dir_colors funcionará, não importa o que aconteça.

Vamos analisar mais a fundo.

Para determinar qual dos esquemas de coloração está causando a lentidão, criamos um ambiente experimental:

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # não tente isso em casa!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

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

12,7 segundos para 10.000 arquivos, não é muito bom.

Aliás, precisa da flag --color=always: embora ele se refira a ls --color=auto, mas ls detecta quando não está conectado ao terminal (por exemplo, por um pipe ou com redirecionamento de saída) e desativa a coloração, se configurado auto. Cara esperto.

Então, o que leva tanto tempo? Nós verificamos com 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
[...]

Uau: 10.000 chamadas lstat(), 10.000 chamadas getxattr() (que todas falham, porque em nosso ambiente não há atributos que o ls procura), 10.000 chamadas capget().

Com certeza isso pode ser otimizado.

Atributo capabilities? Não.

Seguindo as recomendações de um bug de 10 anos atrás, tentamos desativar a verificação de atributo 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

Uau, aceleração para 8 segundos! Eliminamos todas essas chamadas caras getxattr(), e as chamadas capget() também desapareceram, ótimo.

Mas ainda restam essas chamadas incômodas lstat(), embora…

Quantas cores são necessárias?

Então analisamos mais de perto LS_COLORS.

Primeiro simplesmente desativamos essa variável:

$ 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

O quê!?! 13 segundos ainda?

Aparentemente, quando a variável de ambiente LS_COLORS não está definida ou falta apenas um de seus elementos =color:, por padrão, utiliza o banco de dados embutido e ainda usa cores. Portanto, se você quiser desativar a coloração para um tipo específico de arquivo, você precisa sobrescrevê-la com =: ou 00 no arquivo DIR_COLORS.

Após muitas tentativas e erros, restringimos a busca para isso:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

que é escrito como

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

Isso significa: não colore arquivos nem por atributo capabilities, nem por bits setuid/setgid, nem pelo flag de executabilidade.

Acelerando ls

E se nenhuma dessas verificações for feita, então as chamadas lstat() desaparecem, e agora é outra história:

$ 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 segundos na lista de 10.000 arquivos, um recorde.

Configurando Sherlock

De 13 segundos com configurações padrão para 0,3 segundos com uma pequena configuração LS_COLORS significa um aumento de 40 vezes devido à ausência de setuid / setgid e arquivos executáveis coloridos. Não é uma grande perda.

Claro, agora está configurado no Sherlock para cada usuário.

Mas se você quiser restaurar a coloração, pode simplesmente voltar às configurações padrão:

$ unset LS_COLORS

Mas então, em diretórios com muitos arquivos, não esqueça de preparar um café enquanto isso acontece. ls.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster