segunda-feira, 6 de agosto de 2012

Resolvendo problema "Too many files open" no Linux

Em determinadas situações de missão crítica, os servidores Linux geram uma exceção "Too many files open". Este tipo de problema ocorre quando determinado usuário (inclusive o root) alcança o limite máximo de abertura de arquivos permitida pelo sistema.
 
Como monitorar a quantidade de arquivos abertos?
Através do comando lsof (list open files) é possível verificar todos os arquivos abertos no sistema – incluindo aqueles sem "descritores", ou seja, bibliotecas mapeadas em memória, diretórios, executáveis, entre outros.
Um descritor de um arquivo é um dado estruturado usado pelos programas para buscar uma referência ao arquivo. Em relação a performance do sistema, arquivos sem descritores não impactam no limite de arquivo que poderá ser aberto pelos usuários. Através desse comando, temos uma visão geral. Por exemplo, para saber a quantidade de arquivos abertos (incluindo aqueles sem descritores) do usuário "tomcat", podemos utilizar o comando:
 
lsof | grep tomcat | wc -l
 
Para verificarmos a quantidade de arquivos abertos com os descritores - aqueles que provocam a exceção, utilize o comando abaixo:
 
cat /proc/sys/fs/file-nr
 
Este comando irá exibir uma mensagem similar a apresentada abaixo:
 
3584    0       406486
 
Estas colunas, respectivamente, representam o seguinte:
Primeira coluna (3584) - Total de descritores alocados.
Segunda coluna (0) - Dos descritores alocados (na primeira coluna), este número indica quanto deles estão livres.
Terceira coluna (406486) - Total de descritores que podem ser alocados.
 
Observação: Existe certa especulação a respeito da segunda coluna. Algumas pessoas dizem que ela representa o número de descritores alocados, mas é justamente o contrário. Ela indica o número livre de descritores, dos alocados. Neste exemplo, temos 3584 descritores alocados, sendo que nenhum deles está livre, e o sistema poderá alocar 406486.
 
Para encontrar o número de arquivos abertos (com descritores) no sistema, pegue a primeira coluna e subtraia da segunda (3584 - 0). Neste caso particular (servidor de missão crítica em produção - com um SGBD MySQL e um Container J2SE rodando), não existem descritores livres.
 
Quantos arquivos (com descritores) um determinado usuário poderá abrir?
Com o comando abaixo, podemos descobrir o número máximo de arquivos que um usuário pode abrir através da linha "open files".
Observe que o comando deve ser executado pelo próprio usuário.
 
ulimit -a
 
O comando exibirá a seguinte tabela (este comando foi realizado por um usuário comum de micro desktop):
 
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7679
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7679
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
 
Observe que a linha "open files" apresenta um limite de 1024 arquivos (com descritores).
 
Entendendo o problema:
Quando uma exceção "Too many open files" ocorre, significa que, o número de arquivos (com descritores) que foram abertos pelo usuário ultrapassou o limite estabelecido em "open files" do comando "ulimit -a". Lembre-se que o limite de "lsof | grep usuario | wc -l" representa um valor muito acima de arquivos abertos por "usuario".
 
Como obter o real número de arquivos abertos:
Podemos obter quais processos estão sendo utilizados pelo usuário com o comando (faça as devidas adaptações no "cut" para indicar somente o valor de id do processo no resultado completo de "lsof | grep guilherme":
 
lsof | grep guilherme | cut -c11-15 | uniq
 
Podemos então, para cada processo exibido, verificar quais arquivos com descritores estão abertos com o comando (para o processo de PID 6340):
 
ls -l /proc/6340/fd/
 
E o total de arquivos abertos para aquele processo com:
 
lsof | grep guilherme | wc -l
 
Enfim, não é tão simples assim descobrir a quantidade de arquivos com descritores abertos por determinado usuário.
Podemos fazer isso com o script abaixo:
 
#!/bin/sh
##########################################################################
# SCRIPT que conta o número de arquivos abertos pelo usuário "C_USER"
 
C_USER=guilherme
TOTAL=0
 
for iFile in `lsof | grep $C_USER | cut -c11-15 | uniq`
do
  VALOR=`ls -l /proc/$iFile/fd/ | wc -l`
  TOTAL=$(($VALOR + $TOTAL))
done
 
echo
echo "Total de arquivos abertos pelo usuário $C_USER: $TOTAL"
echo
##########################################################################
 
Com esse SCRIPT podemos saber exatamente quantos arquivos com descritores estão abertos pelo usuário. Rodando esse script no meu micro, o resultado apresentado foi:
 
Total de arquivos abertos pelo usuário guilherme: 826
 
OBS. O comando "cut" pega exatamente as colunas que representam o número do processo. Para validar o script acima, execute o comando abaixo e verifique se o PID dos processos foi recuperado com sucesso (talvez seja necessário alterar para "cut -c11-16")
 
lsof | grep guilherme | cut -c11-15
 
Voltando ao assunto que interessa.
O valor apresentado por esse script sempre deverá ser inferior ao "open files" do comando "ulimit -a", caso contrário:
Too many open files
 
Resolvendo o problema:
Aumentar o limite máximo de arquivos com descritores que podem ser abertos pelo usuário que impactou no problema. Como podemos fazer isso?
Acrescente as linhas abaixo no arquivo "/etc/security/limits.conf" para o respectivo usuário (neste caso, guilherme):
 
guilherme             soft    nofile          2048
guilherme             hard    nofile          63536
 
O limite soft, é o limite máximo suportado pelo usuário. Porém, o usuário poderá aumentar esse limite até o limite "hard". Esses limites são definidos pelo root, e o usuário em questão poderá aumentar seu limite além do soft (2048, neste caso) com o comando:
 
ulimit -n 2048
 
Portanto, em primeiro lugar, como root, defina os valores limites soft e hard para o usuário. Entre com o usuário e aumente o número máximo de arquivos abertos com "ulimit -n NUMERO", se necessário.

Obrigado pela leitura.

Nenhum comentário:

Postar um comentário