Corrigindo "fork: Resource temporarily unavailable"
O que significa "fork: Resource temporarily unavailable"?
Conclusão: Uma chamada a
fork(2)(ouclone(2)) foi temporariamente recusada porque um limite foi atingido. O kernel retornaEAGAIN, e o shell ou aplicação imprime "Resource temporarily unavailable". Nem sempre é pouca memória; a causa geralmente é 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 é convertido em string e impresso.
$ ./myapp fork: retry: Resource temporarily unavailable
bash: fork: retry: Resource temporarily unavailable bash: fork: Resource temporarily unavailable
O próprio shell pode emiti-lo, caso em que você não consegue nem executar um novo comando. O ponto-chave: isto não é um problema de disco ou rede. Você esgotou o orçamento do kernel para "quantas tarefas podem existir ao mesmo tempo", então apenas a criação de novas é bloqueada. Processos existentes continuam executando, então o sintoma é estritamente "não consigo iniciar nada novo".
Premissas (ambiente alvo)
- SO: Ubuntu / Linux típico (baseado em systemd)
- Sintoma:
fork/clonefalha comResource temporarily unavailable - Você pode ler
ulimit//proc/systemctl(algumas alterações permanentes precisam desudo)
Por que fork falha com EAGAIN?
Conclusão: A causa é uma de quatro: (1) limite de processos por usuário (
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 memória. Na maioria das vezes é (1) ou o baseado em cgroup (3).
Aqui estão os caminhos que fazem fork retornar EAGAIN, agrupados por qual limite é atingido.
| Causa | O limite real | Onde começar a verificar |
|---|---|---|
| Limite de processos por usuário | 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 memória | Não consegue alocar estruturas de tarefas | free -h / dmesg |
Trabalhe do orçamento mais próximo para fora. Comece com "o limite deste usuário (ulimit -u)", depois "o TasksMax do cgroup que agrupa o serviço", e finalmente "o pid_max / threads-max do sistema". Aplicações web e containers que criam muitas threads geralmente atingem o limite do cgroup (3) primeiro.
ulimit -u é descrito como "contagem de processos", mas internamente o Linux conta cada thread como uma tarefa. Uma aplicação multithread pode atingir o limite "com apenas poucos processos", então sempre conte o uso atual em unidades de thread.
Como verifico a contagem e limites atuais de processos / threads?
Conclusão: Primeiro leia o limite com
ulimit -u, conte o uso atual comps -eLf | wc -l(ou por usuário), depois compare. Se o uso está no limite, esse orçamento é o culpado.
Comece com o limite em vigor para seu shell atual.
$ ulimit -u
4096
Depois, conte as tarefas atuais (threads incluídas). O -L em ps -eLf expande cada thread para sua própria linha, correspondendo à 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) está logo abaixo do limite (4096), o orçamento está gasto. Para ver qual processo está 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 é a origem real. Se é um vazamento não intencional de threads (pool de conexões ou contagem de workers mal configurados), suspeite da aplicação antes de elevar qualquer limite.
Antes de elevar um limite, decida se o uso é "um número saudável que é simplesmente muito pequeno" ou "anormalmente alto por causa de um vazamento". Encobrir um vazamento elevando o limite só faz recorrer mais tarde com um teto mais alto.
Como corrijo o limite por usuário (ulimit -u / nproc)?
Conclusão: Temporariamente você pode ampliar com
ulimit -u <n>, mas para aplicar entre logins, definanprocem/etc/security/limits.conf(oulimits.d/). Daemons não recebem limits.conf, então precisam da configuração 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 configuração 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 é o valor padrão, hard é o teto que você pode elevar. Estes são aplicados via pam_limits.so do PAM, então você deve fazer login novamente após editar. No Ubuntu, o layout recomendado é colocar arquivos em /etc/security/limits.d/*.conf, que são lidos após o arquivo principal.
limits.conf se aplica apenas a sessões de login que passam pelo PAM. Não é aplicado a daemons (Nginx, MySQL, etc.) iniciados pelo systemd. Defina limites de processo para serviços com as configurações de cgroup / systemd na próxima seção. Confundir estes leva a "mudei mas nada aconteceu".
E se o cgroup / systemd TasksMax for a causa?
Conclusão: Serviços e sessões de login gerenciados pelo systemd são governados pelo
pids.maxdo cgroup (=TasksMax). Se editarlimits.confnão muda nada, este é quase sempre o culpado. Verifique o valor atual comsystemctl show -p TasksMax, depois eleve com um drop-in.
O systemd agrupa cada serviço e cada sessão de usuário 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 é uma porcentagem do pid_max do kernel (15% por padrão); sem um override por serviço, este padrão se aplica. Para elevar o limite de um serviço, crie um drop-in.
$ sudo systemctl edit nginx.service
Escreva o seguinte no editor (TasksMax sob [Service]).
[Service] TasksMax=infinity
Aplique após salvar.
$ sudo systemctl daemon-reload $ sudo systemctl restart nginx.service $ systemctl show -p TasksMax nginx.service
O orçamento para usuários de login fica em UserTasksMax (/etc/systemd/logind.conf), aplicado ao user-<UID>.slice. Verifique isto também se um usuário 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 após confirmar que a causa não é um vazamento; normalmente defina um valor concreto de "necessário + margem".
Como ajusto os limites do sistema (pid_max / threads-max)?
Conclusão: Se mesmo o total entre todos os usuários é insuficiente, eleve
kernel.pid_maxekernel.threads-max. Altere temporariamente comsysctle persista em/etc/sysctl.d/. Aplica-se a hosts com muitos containers ou alta concorrência.
Verifique os tetos do sistema para PIDs e threads simultâneos.
$ 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 milhões). Mas cada thread consome memória do kernel, então elevar cegamente esgota a memória primeiro. O padrão de threads-max é auto-calculado a partir da RAM, então verifique a margem com free -h antes de elevar.
Mesmo após elevar pid_max / threads-max, se a memória é curta, fork vai falhar com ENOMEM (Cannot allocate memory). Quando EAGAIN vira ENOMEM, memória -- não o limite -- é o gargalo. Veja Lidando com o OOM killer.
Recuperação de emergência: quando nem o shell consegue fazer fork
Conclusão: Mesmo quando você não 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 orçamento sem criar nenhum comando externo.
Quando fork está esgotado, você não pode nem iniciar comandos externos como ps ou /usr/bin/kill. Aqui você luta apenas com builtins do bash, que não criam um novo processo.
# O kill builtin (nao o externo /bin/kill) sinaliza um job ou PID $ kill %1 $ kill 2314
Você pode até 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 própria sessão descontrolada, ou trabalhe de outra sessão de login existente (uma conexão SSH que ainda está ativa). O último recurso é 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 conexões, mantenha uma sessão de recuperação conectada. Incidentes de esgotamento de limites tendem a "bloquear novos logins quando você percebe", então uma sessão reserva separada da sua de trabalho é um salva-vidas.
Checklist quando ainda não resolve
Conclusão: Um fork EAGAIN significa que "o orçamento de contagem de tarefas está esgotado" está confirmado. Verifique do orçamento mais próximo para fora --
ulimit -upor usuário ->TasksMaxdo cgroup ->pid_max/threads-maxdo sistema -- e a causa converge para uma dessas camadas. Não esqueça de confirmar que não há 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? - [ ] É uma contagem saudável, ou um vazamento de threads / processos?
- [ ] Decidiu se o alvo é uma sessão de login ou um daemon systemd (
limits.confvsTasksMax)? - [ ]
systemctl show -p TasksMax <servico>é grande o suficiente? - [ ] Se o total global é insuficiente, verificou
kernel.pid_max/kernel.threads-max? - [ ] Após elevar um limite, há margem de memória (
free -h)?