Corrigindo "fork: Resource temporarily unavailable"
O que significa "fork: Resource temporarily unavailable"?
Conclusao: Uma chamada a
fork(2)(ouclone(2)) foi temporariamente recusada porque um limite foi atingido. O kernel retornaEAGAIN, 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/clonefalha comResource temporarily unavailable - Voce pode ler
ulimit//proc/systemctl(algumas alteracoes permanentes precisam desudo)
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 (systemdTasksMax), 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 comps -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, definanprocem/etc/security/limits.conf(oulimits.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.maxdo cgroup (=TasksMax). Se editarlimits.confnao muda nada, este e quase sempre o culpado. Verifique o valor atual comsystemctl 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_maxekernel.threads-max. Altere temporariamente comsysctle 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. Usekill,exece 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 -upor usuario ->TasksMaxdo cgroup ->pid_max/threads-maxdo sistema -- e a causa converge para uma dessas camadas. Nao esqueca de confirmar que nao ha vazamento.
- [ ] Distinguiu
EAGAIN(Resource temporarily unavailable) deENOMEM(Cannot allocate memory)? - [ ] Comparou o valor de
ulimit -ucom a contagem atual de threads deps -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.confvsTasksMax)? - [ ]
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)?