ulimit: Entendendo Limites de Recursos

ulimit: Entendendo Limites de Recursos

O Que é o ulimit?

Conclusão: ulimit mostra e altera os limites superiores de recursos (arquivos abertos, processos, memória e mais) que um shell e os processos que ele inicia podem usar.

ulimit é 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 é herdado por processos filhos criados com fork.

As três razões comuns para usá-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 concorrência
  • Diminuir limites para evitar que um script descontrolado esgote recursos

Premissas

  • bash é assumido (ulimit é um builtin do shell; outros shells como zsh o suportam com flags ligeiramente diferentes)
  • A seção de persistência assume uma distro baseada em systemd (família Ubuntu / RHEL)

Limites Soft vs Hard

Conclusão: O limite soft é o que é realmente aplicado; o limite hard é o teto para o limite soft. Um usuário sem privilégios pode aumentar o limite soft até o limite hard, mas apenas root pode aumentar o limite hard.

Cada recurso tem dois valores.

Tipo Significado O que um usuário sem privilégios pode fazer
soft O limite atualmente aplicado Aumentar ou diminuir, até o limite hard
hard O teto que o soft não pode exceder Apenas diminuir (não pode aumentá-lo)

Uma vez que você diminui um limite hard, não pode aumentá-lo novamente dentro daquela árvore 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 exibição mostra o valor soft, mas a definição altera ambos de uma vez -- tenha isso em mente.

Como Verificar os Limites Atuais?

Conclusão: 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

Conclusão: No dia a dia, os quatro que você mais usa são -n (arquivos abertos), -u (processos), -c (core), e -s (stack).

Flag Recurso Uso típico / sintoma
-n arquivos abertos "Too many open files." O limite de file descriptor
-u processos max do usuário "fork: retry: Resource temporarily unavailable"
-c tamanho do core file Se um crash gera core dump (0 desabilita)
-f tamanho de arquivo Tamanho máximo de um único arquivo
-s tamanho da stack Investigando segfaults de recursão profunda
-v memória virtual Limite da memória virtual total do processo
-l max memória bloqueada Quanta memória pode ser mlockada (relevante para BDs)

-u (processos max do usuário) limita a contagem de processos para o usuário inteiro, não apenas este shell. Parece ser por shell, mas é contado em todos os processos pertencentes ao mesmo UID.

Como Alterar um Limite Temporariamente?

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

# 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 é rejeitado.

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

Isso requer aumentar o limite hard, o que um usuário sem privilégios não pode fazer. Como root, você 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 alteração do ulimit alcanca apenas o shell que a executou e seus descendentes. Não altera os limites de um daemon já em execução. Para aplicar limites a um processo ativo, use prlimit.

Como Tornar um Limite Persistente?

Conclusão: Para sessões de login use /etc/security/limits.d/*.conf; para serviços gerenciados pelo systemd use LimitNOFILE= na unit. Eles são aplicados por caminhos diferentes.

Shells de login (via pam_limits)

/etc/security/limits.conf e /etc/security/limits.d/*.conf são aplicados no login pelo módulo 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 é <dominio> <tipo> <item> <valor>, onde dominio é um nome de usuário, @nomegrupo, ou * para todos. As alterações só entram em vigor após você fazer logout e login novamente.

pam_limits não afeta processos que não passam por uma sessão PAM. limits.conf não se aplica a daemons iniciados pelo systemd, o que é uma razão comum para um limite "aumentado" parecer não ter efeito.

Serviços systemd

Para serviços gerenciados pelo systemd, defina o limite na seção [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 padrão de todos os serviços, 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 Execução?

Conclusão: Leia /proc/<PID>/limits ou use prlimit --pid <PID>. prlimit também pode alterar os limites de um processo em execução sem reiniciá-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 única 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"

Conclusão: Conte os file descriptors reais com lsof e compare com o limite. Decida se é 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 está fixada no limite, determine a causa.
  • Vazamento de FD (descritores abertos mas nunca fechados) - corrigir a aplicação e a solução real; aumentar o limite apenas ganha tempo
  • Legitimamente alto (alta concorrência) - aumente o limite usando os passos de persistência

Resumo

  • ulimit gerencia limites de recursos por processo; tenha em mente o modelo de dois níveis 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 serviços systemd -- não confunda os caminhos
  • Para "Too many open files," suspeite de um vazamento de FD antes de aumentar o limite

Próximas Leituras