Quem gerencia servidores Linux compartilhados com cPanel e CloudLinux já deve ter passado por um cenário intrigante: o site fica carregando infinitamente no navegador até retornar ERR_CONNECTION_TIMED_OUT, mas ao checar os limites da conta no CloudLinux (lveinfo), o usuário parece completamente ocioso, com zero de CPU e memória livre.
Esse tipo de travamento silencioso costuma enganar porque as métricas mais óbvias não acusam estouro de recursos. O problema não está na falta de hardware, mas em conflitos internos de execução: processos concorrendo por manipuladores PHP diferentes, travas exclusivas de arquivos de sessão ou filas de backlog de rede saturadas no kernel.
Neste artigo, vamos dissecar um incidente real desse tipo, mostrando como investigar a tabela de processos, inspecionar sockets Unix, rastrear chamadas de sistema com strace e destravar o ambiente pelo terminal.
1. O sintoma do timeout e a análise da tabela de processos#
O problema começou com um domínio específico (domain.com) preso em requisições HTTP que nunca completavam. A primeira ação no terminal foi listar os processos daquele usuário do cPanel (user):
ps aux | grep user
O comando retornou a seguinte fotografia do ambiente:
user 823582 0.2 1.9 244988 230716 ? R 00:26 1:42 spamd child
user 900307 0.0 0.0 49232 11068 ? S 09:12 0:00 dovecot/imap
user 901292 0.0 0.0 49544 11524 ? S 09:15 0:00 dovecot/imap
user 902486 0.6 1.6 211880 197416 ? S 09:19 0:15 spamd child
user 913853 0.2 0.2 98260 24748 ? S 09:57 0:00 php-fpm: pool user_user
user 913949 0.0 0.0 5908 3700 ? S 09:57 0:00 /usr/local/cpanel/bin/splitlogs --dir=/etc/apache2/logs/domlogs --main=node.domain.com --suffix=-bytes_log
user 914085 0.1 0.1 59640 12832 ? R 09:57 0:00 /opt/cpanel/ea-php83/root/usr/bin/php-cgi
user 914126 0.0 0.0 23820 8600 ? R 09:57 0:00 /opt/cpanel/ea-php83/root/usr/bin/php-cgi
user 914127 0.5 0.0 30892 10228 ? R 09:57 0:00 /opt/cpanel/ea-php83/root/usr/bin/php-cgi
user 914138 0.0 0.0 23688 8448 ? S 09:57 0:00 /opt/cpanel/ea-php83/root/usr/bin/php-cgi
O que essa listagem revela#
- Processos em estado R (Running): os PIDs
914085,914126e914127do bináriophp-cgiestavam marcados com a flag R. Isso significa que eles estavam na fila de execução do escalonador do kernel (scheduler), executando instruções ou aguardando chamadas de sistema no espaço de usuário. - Conflito de manipuladores (handlers): a conta já possuía um pool ativo de PHP-FPM em execução (PID
913853). A presença simultânea de instâncias avulsas dephp-cgiindica que requisições do Apache foram desviadas para execução CGI tradicional em vez de serem despachadas via socket para o worker do FPM.
2. Investigando os limites de recursos do CloudLinux LVE#
A primeira suspeita em servidores CloudLinux é que o usuário tenha atingido o teto de Entry Processes (EP) ou processos simultâneos (NPROC). Quando isso acontece, o módulo de kernel kmod-lve segura novas conexões ou recusa chamadas fork().
Para checar os dados consolidados da conta nos últimos minutos:
lveinfo --user user --period=5m
A saída exibiu o seguinte histórico:
+-----------+-----------+----+----+----+---+---+---+-----+-----+-----+-----+---+-----+-----+-----+------+------+------+-----+------+------+------+-----+-----+-----+-----+
|From |To |aCPU|mCPU|lCPU|aEP|mEP|lEP|aVMem|mVMem|lVMem|VMemF|EPf|aPMem|mPMem|lPMem|aNproc|mNproc|lNproc|PMemF|NprocF|aIO |mIO |lIO |aIOPS|mIOPS|lIOPS|
+-----------+-----------+----+----+----+---+---+---+-----+-----+-----+-----+---+-----+-----+-----+------+------+------+-----+------+------+------+-----+-----+-----+-----+
|04-23 09:58|04-23 09:59|2 |2 |100 |0 |0 |20 |0B |0B |0B |0 |0 |1.2MB|1.2MB|1.0GB|0 |0 |100 |0 |0 |148KB |1.0MB |1.0MB|1 |1 |1.0K |
+-----------+-----------+----+----+----+---+---+---+-----+-----+-----+-----+---+-----+-----+-----+------+------+------+-----+------+------+------+-----+-----+-----+-----+
Por que o lveinfo zerado pode induzir ao erro#
- Uso de CPU: o limite alocado era de 100% (1 núcleo), mas o pico foi de apenas 2% (
mCPU=2). - Processos de entrada: o teto era de 20 conexões simultâneas, e o registrado foi zero (
mEP=0) com zero falhas (EPf=0). - Memória física: o limite era de 1 GB, e o consumo não passava de 1,2 MB.
Como todos os contadores de falha (EPf, PMemF, NprocF) estavam zerados, o CloudLinux não estava bloqueando a conta. O travamento vinha de dentro da aplicação ou da pilha de rede.
3. Inspeção do socket unix do PHP-FPM#
Para confirmar se o serviço do PHP-FPM estava congelado ou com a fila cheia, inspecionamos o socket local com o utilitário ss:
ss -lnxp | grep "user"
O retorno foi:
u_str LISTEN 0 4096 /var/cpanel/php-fpm/user/sock 5587329 * 0 users:(("cpanel_php_fpm",pid=914882,fd=10),("cpanel_php_fpm",pid=914576,fd=5),("cpanel_php_fpm",pid=808640,fd=8))
- Estado LISTEN e filas: a coluna
Recv-Qestava em0e o limite de backlog em4096. Isso prova que o socket do PHP-FPM estava completamente desimpedido, pronto para receber conexões. - Conclusão: o daemon do PHP-FPM estava saudável, mas o tráfego do Apache estava sendo desviado para processos
php-cgiavulsos por causa de uma diretiva desalinhada no vhost.
4. Rastreamento de chamadas de sistema com strace#
Como os processos php-cgi continuavam em estado R sem responder e sem consumir CPU relevante, era preciso descobrir em qual chamada de sistema eles estavam parados.
Conectamos o strace ao processo mais ativo (PID 914127):
strace -ff -y -tt -T -s 512 -p 914127
Dois cenários frequentes de travamento silencioso foram identificados:
Cenário a: contenção de travas no arquivo de sessão (session locking)#
No PHP, a função padrão de manipulação de sessões abre o arquivo do usuário em disco com trava exclusiva (flock ou fcntl). Se uma aba do navegador dispara uma chamada demorada e o usuário abre outra página do mesmo site, a segunda requisição fica congelada aguardando a liberação da trava:
09:58:02.102345 flock(8, LOCK_EX) = ? ERESTARTSYS (To be restarted if system call is interrupted)
09:58:05.405912 flock(8, LOCK_EX <waiting...>)
Para confirmar se o descritor de arquivo pertence a uma sessão:
lsof -p 914127 | grep "sess_"
Se o processo estiver apontando para /var/cpanel/php/sessions/ea-php83/sess_[ID], a aplicação está retendo a sessão por tempo excessivo em vez de chamar session_write_close() assim que a leitura dos dados termina.
Cenário b: timeout em requisições de rede externas#
Outro motivo clássico de espera é uma requisição externa (como cURL em plugins do WordPress tentando consultar licenças ou gateways de pagamento) travada em resolvedores de DNS lentos:
09:58:02.200110 connect(9, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0
09:58:02.200450 poll([{fd=9, events=POLLOUT}], 1, 5000) = 0 (Timeout)
O processo PHP fica parado na chamada poll() aguardando resposta até estourar o limite de tempo configurado.
5. Falha na camada de transporte: o timeout do cURL (código 28)#
Ao testar o acesso externo com curl a partir de outra máquina:
curl https://domain.com
O comando retornou após mais de 2 minutos de espera:
curl: (28) Failed to connect to domain.com port 443 after 134437 ms: Couldn't connect to server
O erro 28 significa CURLE_OPERATION_TIMEDOUT. O fato de a conexão expirar após 134 segundos sem receber sequer um pacote de reset (RST) indica que os pacotes SYN iniciais estavam sendo descartados silenciosamente pelo firewall ou pela fila de conexões pendentes do servidor.
Saturação da fila de aceitação do Apache#
Quando os workers do Apache travam segurando processos PHP emperrados, a fila de aceitação de novas conexões no kernel transborda.
Para verificar se há acúmulo de conexões na pilha TCP:
# Conexões pendentes em handshake
ss -nt state syn-recv
# Backlog na porta HTTPS (443)
ss -tlnp | grep :443
Se a coluna Recv-Q do socket em escuta na porta 443 estiver próxima ou igual ao limite configurado na coluna Send-Q (por exemplo, 511/511), o Apache parou de chamar accept() e o kernel descarta novas requisições silenciosamente.
6. Playbook prático para recuperação do serviço#
Para encerrar os processos órfãos, restaurar o firewall e reconfigurar os manipuladores do PHP-FPM corretamente, execute os passos abaixo:
Passo 1: Encerrar processos PHP travados da conta#
Elimine os binários da conta afetada que estejam retendo arquivos e descritores:
pkill -u user -9 php-cgi
pkill -u user -9 cpanel_php_fpm
O sinal -9 (SIGKILL) força o encerramento imediato pelo kernel, impedindo que processos em loop continuem bloqueando arquivos de sessão.
Passo 2: Limpar e reiniciar as regras de firewall (CSF/iptables)#
Se o firewall bloqueou temporariamente conexões que ficaram repetindo tentativas:
csf -f && csf -r
Isso esvazia as cadeias de regras e reconstrói as tabelas de proteção do CSF.
Passo 3: Reconstruir o pool do PHP-FPM e reiniciar os serviços#
Para corrigir o desalinhamento que fez o Apache invocar php-cgi em vez do FPM:
# Reconstruir os arquivos de vhost e pool do usuário
/usr/local/cpanel/scripts/php-fpm-config --rebuild --user=user
# Reiniciar o daemon do FPM e o Apache
/scripts/restartsrv_cpanel_php_fpm
/scripts/restartsrv_httpd
Boas práticas para prevenir travamentos silenciosos#
- Evite misturar manipuladores PHP: certifique-se de que todas as contas do servidor estejam padronizadas no PHP-FPM ou no lsapi. Ambientes com configurações legadas de CGI geram forks inesperados de processos que fogem do controle do pool.
- Revise o uso de sessões na aplicação: scripts com tarefas pesadas ou chamadas de API externas devem sempre liberar o arquivo de sessão com
session_write_close()antes de processar rotinas longas, evitando que requisições paralelas fiquem bloqueadas emflock. - Monitore as filas do kernel (
Recv-Q): quando o site não responder e o uso de CPU estiver baixo, inspecione a porta 443 comss -tlnp. Se a fila de recebimento estiver cheia, o gargalo está na capacidade do servidor web de consumir conexões aceitas pelo kernel.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários