Corrigindo "fork: Resource temporarily unavailable"

Corrigindo "fork: Resource temporarily unavailable"

O que significa "fork: Resource temporarily unavailable"?

Conclusao: Uma chamada a fork(2) (ou clone(2)) foi temporariamente recusada porque um limite foi atingido. O kernel retorna EAGAIN, e o shell ou aplicacao imprime "Resource temporarily unavailable". Nem sempre e pouca memoria; a causa geralmente e um limite de contagem de processos ou threads.

Este erro aparece no instante em que um programa tenta criar um processo filho ou thread. fork() / clone() retorna EAGAIN (errno 11), que e convertido em string e impresso.

$ ./myapp
fork: retry: Resource temporarily unavailable
bash: fork: retry: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable

O proprio shell pode emiti-lo, caso em que voce nao consegue nem executar um novo comando. O ponto-chave: isto nao e um problema de disco ou rede. Voce esgotou o orcamento do kernel para "quantas tarefas podem existir ao mesmo tempo", entao apenas a criacao de novas e bloqueada. Processos existentes continuam executando, entao o sintoma e estritamente "nao consigo iniciar nada novo".

Premissas (ambiente alvo)

  • SO: Ubuntu / Linux tipico (baseado em systemd)
  • Sintoma: fork / clone falha com Resource temporarily unavailable
  • Voce pode ler ulimit / /proc / systemctl (algumas alteracoes permanentes precisam de sudo)

Por que fork falha com EAGAIN?

Conclusao: A causa e uma de quatro: (1) limite de processos por usuario (RLIMIT_NPROC = ulimit -u), (2) teto de PID / thread do sistema (pid_max / threads-max), (3) limite de tarefas do cgroup (systemd TasksMax), ou (4) esgotamento de memoria. Na maioria das vezes e (1) ou o baseado em cgroup (3).

Aqui estao os caminhos que fazem fork retornar EAGAIN, agrupados por qual limite e atingido.

Causa O limite real Onde comecar a verificar
Limite de processos por usuario RLIMIT_NPROC (ulimit -u) ulimit -u / ps -u <user>
Teto de PID do sistema kernel.pid_max /proc/sys/kernel/pid_max
Teto de threads do sistema kernel.threads-max /proc/sys/kernel/threads-max
Limite de tarefas do cgroup systemd TasksMax (pids cgroup) systemctl show -p TasksMax
Esgotamento de memoria Nao consegue alocar estruturas de tarefas free -h / dmesg

Trabalhe do orcamento mais proximo para fora. Comece com "o limite deste usuario (ulimit -u)", depois "o TasksMax do cgroup que agrupa o servico", e finalmente "o pid_max / threads-max do sistema". Aplicacoes web e containers que criam muitas threads geralmente atingem o limite do cgroup (3) primeiro.

ulimit -u e descrito como "contagem de processos", mas internamente o Linux conta cada thread como uma tarefa. Uma aplicacao multithread pode atingir o limite "com apenas poucos processos", entao sempre conte o uso atual em unidades de thread.

Como verifico a contagem e limites atuais de processos / threads?

Conclusao: Primeiro leia o limite com ulimit -u, conte o uso atual com ps -eLf | wc -l (ou por usuario), depois compare. Se o uso esta no limite, esse orcamento e o culpado.

Comece com o limite em vigor para seu shell atual.

$ ulimit -u
4096

Depois, conte as tarefas atuais (threads incluidas). O -L em ps -eLf expande cada thread para sua propria linha, correspondendo a unidade que fork/clone conta.

# Total de threads no sistema (aprox., inclui 1 linha de cabecalho)
$ ps -eLf | wc -l

# Threads de um usuario especifico
$ ps -L -u www-data | wc -l
3987

Se o uso atual (3987) esta logo abaixo do limite (4096), o orcamento esta gasto. Para ver qual processo esta produzindo tarefas em massa, ordene por contagem de threads (nlwp) decrescente.

$ ps -eo pid,nlwp,user,comm --sort=-nlwp | head
  PID NLWP USER     COMMAND
 2314 1820 www-data java
 1190  214 mysql    mysqld

O processo com NLWP (contagem de threads) descontrolado e a origem real. Se e um vazamento nao intencional de threads (pool de conexoes ou contagem de workers mal configurados), suspeite da aplicacao antes de elevar qualquer limite.

Antes de elevar um limite, decida se o uso e "um numero saudavel que e simplesmente muito pequeno" ou "anormalmente alto por causa de um vazamento". Encobrir um vazamento elevando o limite so faz recorrer mais tarde com um teto mais alto.

Como corrijo o limite por usuario (ulimit -u / nproc)?

Conclusao: Temporariamente voce pode ampliar com ulimit -u <n>, mas para aplicar entre logins, defina nproc em /etc/security/limits.conf (ou limits.d/). Daemons nao recebem limits.conf, entao precisam da configuracao do systemd.

Primeiro amplie apenas o shell atual para confirmar que o sintoma desaparece.

# Elevar o soft limit, ate o hard limit
$ ulimit -u 8192

A configuracao permanente difere por caminho de login. Logins interativos (SSH / console) respeitam limits.conf.

$ sudo nano /etc/security/limits.conf
# <domain> <type> <item> <value>
www-data  soft  nproc  8192
www-data  hard  nproc  16384
*         soft  nproc  4096

soft e o valor padrao, hard e o teto que voce pode elevar. Estes sao aplicados via pam_limits.so do PAM, entao voce deve fazer login novamente apos editar. No Ubuntu, o layout recomendado e colocar arquivos em /etc/security/limits.d/*.conf, que sao lidos apos o arquivo principal.

limits.conf se aplica apenas a sessoes de login que passam pelo PAM. Nao e aplicado a daemons (Nginx, MySQL, etc.) iniciados pelo systemd. Defina limites de processo para servicos com as configuracoes de cgroup / systemd na proxima secao. Confundir estes leva a "mudei mas nada aconteceu".

E se o cgroup / systemd TasksMax for a causa?

Conclusao: Servicos e sessoes de login gerenciados pelo systemd sao governados pelo pids.max do cgroup (= TasksMax). Se editar limits.conf nao muda nada, este e quase sempre o culpado. Verifique o valor atual com systemctl show -p TasksMax, depois eleve com um drop-in.

O systemd agrupa cada servico e cada sessao de usuario em um cgroup e limita a contagem total de tarefas com TasksMax. Primeiro leia o valor em vigor.

# Limite para um servico especifico
$ systemctl show -p TasksMax nginx.service

# Padrao do sistema (tambem UserTasksMax, etc.)
$ systemctl show -p DefaultTasksMax
TasksMax=4915

DefaultTasksMax frequentemente e uma porcentagem do pid_max do kernel (15% por padrao); sem um override por servico, este padrao se aplica. Para elevar o limite de um servico, crie um drop-in.

$ sudo systemctl edit nginx.service

Escreva o seguinte no editor (TasksMax sob [Service]).

[Service]
TasksMax=infinity

Aplique apos salvar.

$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx.service
$ systemctl show -p TasksMax nginx.service

O orcamento para usuarios de login fica em UserTasksMax (/etc/systemd/logind.conf), aplicado ao user-<UID>.slice. Verifique isto tambem se um usuario interativo executando muitos processos ficar travado.

TasksMax=infinity significa "sem limite", mas remover o teto permite que um vazamento arraste todo o sistema (pid_max). Use somente apos confirmar que a causa nao e um vazamento; normalmente defina um valor concreto de "necessario + margem".

Como ajusto os limites do sistema (pid_max / threads-max)?

Conclusao: Se mesmo o total entre todos os usuarios e insuficiente, eleve kernel.pid_max e kernel.threads-max. Altere temporariamente com sysctl e persista em /etc/sysctl.d/. Aplica-se a hosts com muitos containers ou alta concorrencia.

Verifique os tetos do sistema para PIDs e threads simultaneos.

$ cat /proc/sys/kernel/pid_max
$ cat /proc/sys/kernel/threads-max
4194304
65536

Eleve temporariamente com sysctl -w. Persista colocando um arquivo em /etc/sysctl.d/.

# Alteracao temporaria (perdida no reboot)
$ sudo sysctl -w kernel.pid_max=4194304
$ sudo sysctl -w kernel.threads-max=131072

# Persistir
$ echo 'kernel.pid_max = 4194304' | sudo tee /etc/sysctl.d/99-pids.conf
$ sudo sysctl --system

Em sistemas 64-bit pid_max pode chegar a 4194304 (~4,19 milhoes). Mas cada thread consome memoria do kernel, entao elevar cegamente esgota a memoria primeiro. O padrao de threads-max e auto-calculado a partir da RAM, entao verifique a margem com free -h antes de elevar.

Mesmo apos elevar pid_max / threads-max, se a memoria e curta, fork vai falhar com ENOMEM (Cannot allocate memory). Quando EAGAIN vira ENOMEM, memoria -- nao o limite -- e o gargalo. Veja Lidando com o OOM killer.

Recuperacao de emergencia: quando nem o shell consegue fazer fork

Conclusao: Mesmo quando voce nao pode executar um novo comando, comandos builtin do shell executam sem fork. Use kill, exec e controle de jobs para parar os processos descontrolados e liberar o orcamento sem criar nenhum comando externo.

Quando fork esta esgotado, voce nao pode nem iniciar comandos externos como ps ou /usr/bin/kill. Aqui voce luta apenas com builtins do bash, que nao criam um novo processo.

# O kill builtin (nao o externo /bin/kill) sinaliza um job ou PID
$ kill %1
$ kill 2314

Voce pode ate localizar PIDs sem comandos externos, espiando /proc com o echo builtin e globbing.

# Listar seus processos via globbing (nenhum comando externo necessario)
$ for p in /proc/[0-9]*; do echo "$p"; done

Se ainda estiver fora de controle, use exec para substituir sua propria sessao descontrolada, ou trabalhe de outra sessao de login existente (uma conexao SSH que ainda esta ativa). O ultimo recurso e um reboot pelo console / painel da nuvem, mas sem encontrar a causa raiz (a origem do vazamento) vai recorrer.

Antes que o SSH pare de aceitar novas conexoes, mantenha uma sessao de recuperacao conectada. Incidentes de esgotamento de limites tendem a "bloquear novos logins quando voce percebe", entao uma sessao reserva separada da sua de trabalho e um salva-vidas.

Checklist quando ainda nao resolve

Conclusao: Um fork EAGAIN significa que "o orcamento de contagem de tarefas esta esgotado" esta confirmado. Verifique do orcamento mais proximo para fora -- ulimit -u por usuario -> TasksMax do cgroup -> pid_max/threads-max do sistema -- e a causa converge para uma dessas camadas. Nao esqueca de confirmar que nao ha vazamento.

  • [ ] Distinguiu EAGAIN (Resource temporarily unavailable) de ENOMEM (Cannot allocate memory)?
  • [ ] Comparou o valor de ulimit -u com a contagem atual de threads de ps -L?
  • [ ] Identificou o culpado com ps -eo pid,nlwp,... --sort=-nlwp?
  • [ ] E uma contagem saudavel, ou um vazamento de threads / processos?
  • [ ] Decidiu se o alvo e uma sessao de login ou um daemon systemd (limits.conf vs TasksMax)?
  • [ ] systemctl show -p TasksMax <servico> e grande o suficiente?
  • [ ] Se o total global e insuficiente, verificou kernel.pid_max / kernel.threads-max?
  • [ ] Apos elevar um limite, ha margem de memoria (free -h)?

Proximas leituras