Por que (ou como) o número de descritores de arquivos abertos em uso pela raiz excede o ulimit -n?

13

Nosso servidor recentemente ficou sem descritores de arquivo e, com relação a isso, tenho algumas perguntas. ulimit -ndeve me fornecer o número máximo de descritores de arquivos abertos. Esse número é 1024. Verifiquei o número de descritores de arquivos abertos executando lsof -u root |wc -le obtive 2500 fds. Isso é muito mais que 1024, então imaginei que o número 1024 é por processo, não por usuário, como eu pensava. Bem, eu corri lsof -p$PidOfGlassfish|wc -le consegui 1300. Esta é a parte que não entendo. Se ulimit -nnão for o número máximo de processos por usuário ou por processo, para que serve? Não se aplica ao usuário root? E se sim, como eu poderia receber as mensagens de erro sobre a falta de descritor de arquivo?

EDIT: A única maneira de entender ulimit -né se ele aplica o número de arquivos abertos (como indicado no manual do bash) em vez do número de identificadores de arquivos (processos diferentes podem abrir o mesmo arquivo). Se for esse o caso, basta listar o número de arquivos abertos (grepping em '/', excluindo assim os arquivos mapeados na memória) não é suficiente:

lsof -u root |grep /|sort  -k9  |wc -l #prints '1738'

Para realmente ver o número de arquivos abertos, eu precisaria filtrar a coluna de nome para imprimir apenas as entradas exclusivas. Portanto, o seguinte é provavelmente mais correto:

lsof -u root |grep /|sort  -k9 -u |wc -l #prints '604'

O comando acima espera saída no seguinte formato de lsof:

java      32008 root  mem       REG                8,2 11942368      72721 /usr/lib64/locale/locale-archive
vmtoolsd   4764 root  mem       REG                8,2    18624     106432 /usr/lib64/open-vm-tools/plugins/vmsvc/libguestInfo.so

Isso pelo menos me dá um número menor que 1024 (o número relatado por ulimit -n), então isso parece ser um passo na direção certa. "Infelizmente" não estou tendo problemas com a falta de descritores de arquivos, portanto, dificilmente validarei isso.

oligofren
fonte
2
lsof relata mapeamentos de memória e arquivos abertos, para que seu pipeline 'wc' produza uma superestimação do número de descritores de arquivos usados ​​por esse processo.
Richard Kettlewell
aha! agora essa é uma boa informação. Mas não tenho muita certeza de entender. Por "mapeamento de memória", você quer dizer um arquivo mapeado de memória? Isso exigiria um tratamento de arquivo para o meu entendimento, ou de que outra forma o sistema operacional poderia atualizar o arquivo?
11132 oligofren
E o seguinte: Qual seria uma boa maneira de encontrar todos os identificadores de arquivos abertos - aqueles que são realmente afetados pelos limites impostos pelo "ulimit -n"?
precisa
1
Os mapeamentos de memória não requerem um arquivo aberto. Se você deseja listar apenas arquivos abertos, filtrar a saída de lsof é provavelmente a abordagem mais fácil.
21412 Richard Kettlewell
Obrigado, editei minha resposta. Usar ´lsof -u root | grep / | sort -k9 -u´ parece fornecer o que equivale a uma resposta razoável. Este é pelo menos um número menor que ulimit -n.
11111 oligofren

Respostas:

9

Eu testei isso no Linux versão 2.6.18-164.el5 - Red Hat 4.1.2-46. Pude ver que o ulimit é aplicado por processo.

O parâmetro é definido no nível do usuário, mas aplicado a cada processo.

Por exemplo: 1024 era o limite. Vários processos foram iniciados e os arquivos abertos por cada um foram contados usando

ls -l /proc/--$pid--/fd/ | wc -l

Não houve erros quando a soma dos arquivos abertos por vários processos ultrapassou 1024. Também verifiquei a contagem de arquivos exclusivos, combinando os resultados para diferentes processos e contando arquivos exclusivos. Os erros começaram a aparecer apenas quando a contagem de cada processo ultrapassou 1024. (java.net.SocketException: muitos arquivos abertos nos logs do processo)

Escolhido
fonte
Obrigado por testar isso. Você tem alguma idéia de por que lsof -p$PidOfGlassfish|wc -lme deu 1300? Eu estou supondo que as duas abordagens para contar diferem de alguma forma. Caso contrário, talvez o limite não se aplique ao usuário root?
Oligofren
Apenas curioso, por que usar em ls -lvez de ls? Este último possui uma linha extra (por exemplo total 5) quando existem 5 arquivos. Nesse caso, o uso ls -l no exemplo acima relataria 6 e não 5. Eu uso ls /proc/<pid>/fd | wc -l.
starfry
@ starfry Isso é apenas negligência da minha parte. Eu costumo fazer isso passo a passo e ls -lme fornece uma entrada por linha, que depois canalizo para outra coisa. É claro que isso também acontece quando a tubulação é normal ls(mas não de outra forma).
oligofren
3

O ulimit é para identificadores de arquivo. Aplica-se a arquivos, diretórios, soquetes, epolls de tubos, eventfds, timerfds etc etc.

A qualquer momento durante a inicialização do processo, os limites podem ter sido alterados. Visite /proc/<pid>/limitse veja se os valores foram alterados.

Matthew Ife
fonte
3

@oligofren

I também realizou alguns testes para determinar como "ulimits -Sn"para "open files"foi cumprida.

  • Como o pôster Escolhido mencionado no link , o ulimit for "open files"é realmente aplicado por processo. Para ver quais são os limites atuais do processo:

    cat /proc/__process_id__/limits

  • Para determinar quantos arquivos um processo abriu, você precisa usar o seguinte comando:

    lsof -P -M -l -n -d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt' -p __process_id__ -a | awk '{if (NR>1) print}' | wc -l

Explicação do exposto e meu método / resultados de teste

Os "-P -M -l -n"argumentos para lsof estão lá simplesmente para fazer lsof operar o mais rápido possível. Sinta-se livre para tirá-los.

-P - inhibits the conversion of port numbers to port names for network files
-M - disable reporting of portmapper registrations for local TCP, UDP and UDPLITE ports
-l - inhibits the conversion of user ID numbers to login names
-n - inhibits the conversion of network numbers to host names for network files

O "-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"argumento instrui lsofa excluir descritores de arquivo do tipo: cwd / err / ltx / mem / mmap / pd / rtd / txt.

Na página do manual lsof:

   FD         is the File Descriptor number of the file or:

                   cwd  current working directory;
                   Lnn  library references (AIX);
                   err  FD information error (see NAME column);
                   jld  jail directory (FreeBSD);
                   ltx  shared library text (code and data);
                   Mxx  hex memory-mapped type number xx.
                   m86  DOS Merge mapped file;
                   mem  memory-mapped file;
                   mmap memory-mapped device;
                   pd   parent directory;
                   rtd  root directory;
                   tr   kernel trace file (OpenBSD);
                   txt  program text (code and data);
                   v86  VP/ix mapped file;

Eu considerei "Lnn,jld,m86,tr,v86"não aplicável ao Linux e, portanto, não me preocupei em adicioná-los à lista de exclusão. Eu não tenho certeza "Mxx".

Se seu aplicativo utiliza arquivos / dispositivos mapeados na memória, convém remover "^mem"e "^mmap"da lista de exclusão.

EDITAR --- começar recortar ---

Editar: Encontrei o seguinte link que indica que:

tecnicamente, os arquivos .so mapeados na memória não são iguais aos manipuladores de arquivos sobre os quais o aplicativo tem controle. / proc // fd é o ponto de medição para descritores de arquivos abertos

Portanto, se o seu processo usar arquivos mapeados na memória, será necessário filtrar os arquivos * .so.

Além disso, a JVM da Sun armazenará arquivos jar de memória

Um JARfile mapeado na memória, nesse caso, o arquivo que contém as "classes JDK". Ao mapear um JAR na memória, você pode acessar os arquivos nele com muita eficiência (em vez de lê-lo desde o início). A Sun JVM mapeará na memória todos os JARs no caminho de classe; se o código do aplicativo precisar acessar um JAR, você também poderá mapeá-lo na memória.

Portanto, coisas como tomcat / glassfish também mostrarão arquivos jar mapeados na memória. Eu não testei se isso conta até o "ulimit -Sn"limite.

EDIT --- final snip ---

Empiricamente, descobri que não"cwd,rtd,txt" são contados com relação ao limite de arquivos por processo (ulimit -Sn).

Não tenho certeza se "err,ltx,pd"são contados no limite do arquivo, pois não sei como criar identificadores de arquivo desses tipos de descritores.

O "-p __process_id__"argumento se restringe lsofa retornar apenas informações para o __process_id__especificado. Remova isso se desejar obter uma contagem para todos os processos.

O "-a"argumento é usado para AND nas seleções (ou seja, os argumentos "-p" e "-d").

A "awk '{if (NR>1) print}'"instrução é usada para pular o cabeçalho que é lsofimpresso em sua saída.

Eu testei usando o seguinte script perl:

File: test.pl
---snip---
#!/usr/bin/perl -w
foreach $i (1..1100) {
  $FH="FH${i}";
  open ($FH,'>',"/tmp/Test${i}.log") || die "$!";
  print $FH "$i\n";
}
---snip---

Eu tive que executar o script no depurador perl para garantir que o script não termine e libere os descritores de arquivo.

Executar: perl -d test.pl

No depurador do perl, você pode executar o programa digitando ce pressionando enter e, se você ulimit -Sntiver um valor de 1024 , verá que o programa para após a criação do Test1017.logarquivo /tmp.

Se você agora identificar o pid do processo perl e usar o lsofcomando acima , verá que ele também gera 1024 .

Remova "wc -l"e substitua por a "less"para ver a lista de arquivos contados no limite de 1024 . Remova o "-d ^....."argumento também para ver que os descritores cwd,txte não contam para o limite.rtd

Se você executar agora "ls -l /proc/__process_id__/fd/ | wc -l", verá um valor de 1025 retornado. Isso ocorre porque foi lsadicionado um "total 0"cabeçalho à saída que foi contado.

Nota:

Para verificar se o sistema operacional está ficando sem descritores de arquivo, é melhor comparar o valor de:

cat /proc/sys/fs/file-nr | awk '{print $1}'

com

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt documenta o que file-nre o que file-maxsignifica.

Jinesh Choksi
fonte
0

Parece que seu raciocínio é algo como "eu tenho que diminuir esse limite para não ficar com descritores preciosos". A verdade é exatamente o contrário - se o servidor ficou sem descritores de arquivo, você precisa aumentar esse limite de 1.024 para algo maior. Para uma glassfishimplementação realista , 32.768 é razoável.

Pessoalmente, sempre elevo o limite para cerca de 8.192 em todo o sistema - 1.024 é simplesmente ridículo. Mas você vai querer aumentar glassfishmais. Verifique /etc/security/limits.conf. Você pode adicionar uma entrada especial para o usuário glassfishexecutar como.

David Schwartz
fonte
Não tenho certeza de como você poderia me interpretar com o seguinte significado :-) O que eu queria saber é por que isso não parece se aplicar. Vou definir isso mais alto, mas quero entender como funciona também. Se o limite é 1024, como o Glassfish poderia ter 1300 alças?
precisa
'lsof -u root | grep / | sort -k9 -u' imprime as entradas exclusivas do descritor de arquivo. Eu acho que o número de linhas disso é o número real que ulimit -n se aplica.
Oligofren
0

Você quer dar uma olhada nos limites de todo o sistema definidos em / proc / sys / fs / file-max e ajustá-lo lá (até a próxima reinicialização) ou definir fs.file-max no sysctl.conf para torná-lo permanente. Isso pode ser útil - http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html

rnxrx
fonte
1
Esse comentário sobre o bash não é exato. O ulimit impõe um conjunto de limites por ID de usuário para processos iniciados pelo shell, o que é praticamente tudo graças à maneira como a árvore de processos é gerada no Unix como sistemas operacionais. Não é festança.
EightBitTony
Desculpe - irá editar, mas comentar sobre os limites do sistema ainda permanece.
Rnxrx
É muito improvável que ele esteja atingindo os limites do sistema. Possível, mas muito improvável.
David Schwartz
EightBitTony: ulimit não define ulimit por conjunto de limites de ID do usuário. É por processo quando os pam_limits são aplicados. O ulimit que é "por usuário" é o "ulimit -u" "O número máximo de processos disponíveis para um único usuário"
Nenhum usuário
0

Erro comum ao comparar o resultado da chamada lsof bruta com o suposto limite.

Para o limite global (/ proc / sys / fs / file-max), consulte / proc / sys / fs / file-nr -> o primeiro valor indica o que é usado e o último valor é o limite

O limite do OpenFile é para cada processo, mas pode ser definido em um usuário, consulte o comando "ulimit -Hn" para limites do usuário e consulte /etc/security/limits.conf para obter definições. Geralmente aplicado com "usuário do aplicativo", por exemplo: "tomcat": defina o limite de 65000 para o usuário tomcat, que será aplicado no processo java executado.

Se você deseja verificar o limite aplicado em um processo, obtenha seu PID e, em seguida: cat / proc / $ {PID} / limits Se você deseja verificar quantos arquivos são abertos por um processo, obtenha seu PID e, em seguida: ls -1 / proc / {PID} / fd | wc -l (note que ls é 'menos um', para não confundir com 'menos el')

Se você quiser saber detalhes com lsof, mas apenas para os manipuladores de arquivos que contam para o limite, tente estas opções: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Observação: os 'arquivos' são arquivos / conexões pipe / tcp / etc.

Observe que às vezes você provavelmente precisará ser root ou usar o sudo para obter o resultado correto para os comandos; sem privilégios, às vezes você não tem erro, apenas menos resultados.

e, finalmente, se você quiser saber quais 'arquivos' no seu sistema de arquivos são acessados ​​por um processo, dê uma olhada em: lsof -p {PID} | grep / | awk '{print $ 9}' | classificar | uniq

diverta-se !

Ronan Kerdudou
fonte