Anatomia de um deadlock silencioso no CloudLinux e cPanel: processos fantasmas, travas de sessão e filas TCP
Voltar para blog

Anatomia de um deadlock silencioso no CloudLinux e cPanel: processos fantasmas, travas de sessão e filas TCP

11/10/2026 · 6 min · Infraestrutura

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#


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#

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))

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#

  1. 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.
  2. 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 em flock.
  3. Monitore as filas do kernel (Recv-Q): quando o site não responder e o uso de CPU estiver baixo, inspecione a porta 443 com ss -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:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários