ulimit: Entendendo Limites de Recursos

ulimit: Entendendo Limites de Recursos

O Que e o ulimit?

Conclusao: ulimit mostra e altera os limites superiores de recursos (arquivos abertos, processos, memoria e mais) que um shell e os processos que ele inicia podem usar.

ulimit e um builtin do shell (no bash e shells similares) que chama getrlimit(2) / setrlimit(2) do kernel para ler e definir limites de recursos. Um limite se aplica por processo e e herdado por processos filhos criados com fork.

As tres razoes comuns para usa-lo:

  • Diagnosticar erros de esgotamento de limites como "Too many open files"
  • Aumentar limites para que bancos de dados e servidores web possam lidar com sua concorrencia
  • Diminuir limites para evitar que um script descontrolado esgote recursos

Premissas

  • bash e assumido (ulimit e um builtin do shell; outros shells como zsh o suportam com flags ligeiramente diferentes)
  • A secao de persistencia assume uma distro baseada em systemd (familia Ubuntu / RHEL)

Limites Soft vs Hard

Conclusao: O limite soft e o que e realmente aplicado; o limite hard e o teto para o limite soft. Um usuario sem privilegios pode aumentar o limite soft ate o limite hard, mas apenas root pode aumentar o limite hard.

Cada recurso tem dois valores.

Tipo Significado O que um usuario sem privilegios pode fazer
soft O limite atualmente aplicado Aumentar ou diminuir, ate o limite hard
hard O teto que o soft nao pode exceder Apenas diminuir (nao pode aumenta-lo)

Uma vez que voce diminui um limite hard, nao pode aumenta-lo novamente dentro daquela arvore de processos (aumentar requer root, ou seja, CAP_SYS_RESOURCE). No ulimit, flags selecionam o alvo.

$ ulimit -Sn        # mostra o limite soft de arquivos abertos
$ ulimit -Hn        # mostra o limite hard de arquivos abertos
  • -S: atua no limite soft
  • -H: atua no limite hard
  • Se omitido: a exibicao mostra o valor soft, mas a definicao altera ambos de uma vez -- tenha isso em mente.

Como Verificar os Limites Atuais?

Conclusao: ulimit -a lista o limite soft atual para cada recurso; use uma flag individual como -n para inspecionar um recurso.

$ ulimit -a
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 15363
max locked memory           (kbytes, -l) 8192
max memory size             (kbytes, -m) unlimited
open files                          (-n) 1024
pipe size                (512 bytes, -p) 8
stack size                  (kbytes, -s) 8192
max user processes                  (-u) 15363
virtual memory              (kbytes, -v) unlimited

-a imprime valores soft. Para ver todos os limites hard de uma vez, use ulimit -aH.

$ ulimit -aH        # limites hard para cada recurso

Os Principais Tipos de Recursos

Conclusao: No dia a dia, os quatro que voce mais usa sao -n (arquivos abertos), -u (processos), -c (core), e -s (stack).

Flag Recurso Uso tipico / sintoma
-n arquivos abertos "Too many open files." O limite de file descriptor
-u processos max do usuario "fork: retry: Resource temporarily unavailable"
-c tamanho do core file Se um crash gera core dump (0 desabilita)
-f tamanho de arquivo Tamanho maximo de um unico arquivo
-s tamanho da stack Investigando segfaults de recursao profunda
-v memoria virtual Limite da memoria virtual total do processo
-l max memoria bloqueada Quanta memoria pode ser mlockada (relevante para BDs)

-u (processos max do usuario) limita a contagem de processos para o usuario inteiro, nao apenas este shell. Parece ser por shell, mas e contado em todos os processos pertencentes ao mesmo UID.

Como Alterar um Limite Temporariamente?

Conclusao: Executar algo como ulimit -Sn 4096 afeta apenas o shell atual e os processos que ele inicia depois; fechar o shell reverte a alteracao.

# Aumentar o limite soft de arquivos abertos para 4096 (dentro do limite hard)
$ ulimit -Sn 4096

# Verificar
$ ulimit -Sn
4096

Solicitar mais do que o limite hard e rejeitado.

$ ulimit -Sn 999999
bash: ulimit: open files: cannot modify limit: Operation not permitted

Isso requer aumentar o limite hard, o que um usuario sem privilegios nao pode fazer. Como root, voce pode alterar ambos de uma vez:

# somente root. Define soft e hard juntos para 65536
$ sudo bash -c 'ulimit -n 65536; exec your-server'

Uma alteracao do ulimit alcanca apenas o shell que a executou e seus descendentes. Nao altera os limites de um daemon ja em execucao. Para aplicar limites a um processo ativo, use prlimit.

Como Tornar um Limite Persistente?

Conclusao: Para sessoes de login use /etc/security/limits.d/*.conf; para servicos gerenciados pelo systemd use LimitNOFILE= na unit. Eles sao aplicados por caminhos diferentes.

Shells de login (via pam_limits)

/etc/security/limits.conf e /etc/security/limits.d/*.conf sao aplicados no login pelo modulo PAM pam_limits. Isso cobre shells iniciados por login SSH ou login.

# /etc/security/limits.d/90-nofile.conf
*        soft    nofile    8192
*        hard    nofile    65536
deploy   soft    nproc     4096

O formato e <dominio> <tipo> <item> <valor>, onde dominio e um nome de usuario, @nomegrupo, ou * para todos. As alteracoes so entram em vigor apos voce fazer logout e login novamente.

pam_limits nao afeta processos que nao passam por uma sessao PAM. limits.conf nao se aplica a daemons iniciados pelo systemd, o que e uma razao comum para um limite "aumentado" parecer nao ter efeito.

Servicos systemd

Para servicos gerenciados pelo systemd, defina o limite na secao [Service] da unit.

# /etc/systemd/system/myapp.service.d/override.conf
[Service]
LimitNOFILE=65536
LimitNPROC=4096
$ sudo systemctl daemon-reload
$ sudo systemctl restart myapp

Para alterar o padrao de todos os servicos, edite DefaultLimitNOFILE= em /etc/systemd/system.conf. Verifique o valor efetivo com systemctl show myapp -p LimitNOFILE.

Como Inspecionar os Limites de um Processo em Execucao?

Conclusao: Leia /proc/<PID>/limits ou use prlimit --pid <PID>. prlimit tambem pode alterar os limites de um processo em execucao sem reinicia-lo.

$ cat /proc/1234/limits
Limit                     Soft Limit  Hard Limit  Units
Max open files            1024        524288      files
Max processes             15363       15363       processes
...

prlimit verifica e altera limites em uma unica linha.

# Inspecionar
$ prlimit --pid 1234 --nofile

# Alterar soft/hard de um processo em execucao para 8192 (pode precisar de privilegios)
$ sudo prlimit --pid 1234 --nofile=8192:8192

# Iniciar um comando com um limite aplicado
$ prlimit --nofile=4096:4096 ./myserver

Corrigindo "Too many open files"

Conclusao: Conte os file descriptors reais com lsof e compare com o limite. Decida se e um vazamento de FD ou um limite genuinamente insuficiente antes de agir.

"Too many open files" significa que o limite de arquivos abertos (-n) foi atingido. Resolva da seguinte forma.

  1. Identifique o PID do processo afetado
  2. Verifique seu limite efetivo (cat /proc/<PID>/limits)
  3. Conte quantos descritores ele tem abertos atualmente
# Contar os FDs que um processo tem abertos
$ lsof -p 1234 | wc -l
  1. Se a contagem esta fixada no limite, determine a causa.
  • Vazamento de FD (descritores abertos mas nunca fechados) - corrigir a aplicacao e a solucao real; aumentar o limite apenas ganha tempo
  • Legitimamente alto (alta concorrencia) - aumente o limite usando os passos de persistencia

Resumo

  • ulimit gerencia limites de recursos por processo; tenha em mente o modelo de dois niveis soft/hard
  • Altere temporariamente com ulimit -Sn N; inspecione com ulimit -a, /proc/<PID>/limits, ou prlimit
  • Persista via limits.d/*.conf para logins, ou LimitNOFILE= da unit para servicos systemd -- nao confunda os caminhos
  • Para "Too many open files," suspeite de um vazamento de FD antes de aumentar o limite

Proximas Leituras