Debugging de baixo nível no CloudLinux: syscalls, LVE e o perigo dos limites ilimitados
Voltar para blog

Debugging de baixo nível no CloudLinux: syscalls, LVE e o perigo dos limites ilimitados

14/09/2026 · 3 min · Servidores

Em servidores web rodando cPanel sobre CloudLinux, a proposta central é o isolamento de recursos através do LVE (Lightweight Virtual Environment). No entanto, entre o que está configurado na interface gráfica e o que o Kernel Linux realmente aplica aos processos, podem existir discrepâncias perigosas.

Recentemente, auditei os limites de recursos de uma conta em um servidor de produção (Enterprise Linux) para validar a saúde dos processos em execução e checar se as cotas nominais batiam com a realidade do /proc.

Abaixo, compartilho o passo a passo da análise, comandos de CLI do LVE, rastreio de chamadas com strace e como configurar limites defensivos.

1. O ponto de partida: métricas com lveinfo#

Para entender o comportamento da conta (user_app), extraí o histórico minuto a minuto pela linha de comando:

lveinfo --user user_app

A saída retornou as métricas do módulo kmod-lve:

+-----------+-----------+----+----+----+---+---+---+-----+-----+-----+-----+---+------+------+-----+------+------+------+-----+------+-----+-----+---+-----+-----+-----+
|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-06 14:38|04-06 14:39|30  |30  |400 |1  |1  |0  |0B   |0B   |0B   |0    |0  |14.9MB|14.9MB|0B   |3     |3     |0     |0    |0     |0B   |0B   |0B |0    |0    |0    |
|04-06 14:39|04-06 14:40|29  |29  |400 |1  |1  |0  |0B   |0B   |0B   |0    |0  |16.4MB|16.4MB|0B   |3     |3     |0     |0    |0     |0B   |0B   |0B |0    |0    |0    |
|04-06 14:47|04-06 14:48|33  |33  |400 |1  |1  |0  |0B   |0B   |0B   |0    |0  |16.7MB|16.7MB|0B   |3     |3     |0     |0    |0     |1.1KB|1.1KB|0B |0    |0    |0    |
+-----------+-----------+----+----+----+---+---+---+-----+-----+-----+-----+---+------+------+-----+------+------+------+-----+------+-----+-----+---+-----+-----+-----+

O que esses dados revelam:#

  1. CPU (SPEED): O limite configurado (lCPU) estava em 400 (equivalente a 4 núcleos completos). O pico real (mCPU) foi de apenas 33 (3,3% de 1 core).
  2. Entry Processes (EP): Apenas 1 conexão concorrente ativa, sem nenhum fault (EPf = 0).
  3. Memória Física (PMem): O consumo real era de ~16 MB, mas o limite configurado (lPMem) marcava 0B.

No CloudLinux, o valor 0 ou 0B em memória e processos significa Ilimitado. A conta estava autorizada no Kernel a alocar toda a RAM do host caso quisesse.

2. Inspeção de processos e amostragem com strace#

Listei os processos ativos do usuário:

ps faux | grep user_app

Localizei processos do webmaild, php-fpm e um worker do LiteSpeed PHP (lsphp, PID 2461052).

Para verificar se o processo estava bloqueado em I/O ou sofrendo contenção sem usar ferramentas invasivas (como o gdb, que congela threads com SIGSTOP e causa timeouts em produção), coletei a volumetria de syscalls com strace -c (lembre-se de executar como root/sudo, pois o attach em processos de outros usuários exige CAP_SYS_PTRACE):

strace -p 2461052 -c

Resultado da amostragem:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 91.88    0.695514        9398        74        15 wait4
  7.69    0.058183        1662        35           clone
  0.21    0.001621          22        73        36 pselect6
  0.07    0.000516           7        73           sysinfo
  0.06    0.000435          12        35           accept
  0.04    0.000312           4        70           rt_sigprocmask
  0.03    0.000195           5        37        36 rt_sigreturn
  0.02    0.000179           5        35           close
------ ----------- ----------- --------- --------- ----------------
100.00    0.756955        1752       432        87 total

Análise da execução:#

3. Descritores de arquivo e memória real (RSS vs. VSZ)#

Verifiquei a quantidade de arquivos regulares abertos:

lsof -u user_app | grep REG | wc -l
# Retorno: 423

Comparando com o limite do processo no /proc:

cat /proc/2461052/limits | grep "Max open files"
# Max open files            16384                16384                files

Com o limite em 16.384, a margem de descritores estava segura.

Em seguida, medi a memória física real (RSS) contra o espaço virtual (VSZ):

ps -o rss,vsz,command -p $(pgrep -u user_app)
  RSS    VSZ COMMAND
36256 127676 lsphp
56684  73144 webmaild - serving 192.0.2.10
31388 104864 php-fpm: pool user_chatmgfi

O consumo somado era de apenas ~121 MB de RSS, descartando qualquer vazamento de memória ativo.

4. O perigo dos limites globais ilimitados#

Ao auditar a tabela de limites padrão do CloudLinux:

lvectl list default
      ID   SPEED    PMEM    VMEM      EP   NPROC      IO    IOPS
 default     400      0K      0K       0       0       0       0
    1000     400      0K      0K       0       0       0       0
    1001     400      0K      0K       0       0       0       0

Todas as contas que herdavam o perfil default estavam com:

Embora o PHP possua a trava memory_limit = 512M no php.ini, essa proteção é apenas individual por requisição. Ela não impede que 30 workers concorrentes, processos de Webmail e chamadas Cron consumam toda a RAM física do servidor, acionando o OOM Killer do Kernel.

5. Plano de ajuste e limites defensivos#

Para garantir a estabilidade global do servidor sem provocar lentidão abrupta:

# Definir 1GB de RAM física máxima por usuário (evita pânico de OOM)
lvectl set default --pmem=1024M

# Limitar a 20 conexões simultâneas de entrada (controla o Load)
lvectl set default --ep=20

# Limitar o total de processos concorrentes
lvectl set default --nproc=100

# Reaplicar limites a todos os containers ativos
lvectl reapply

Monitoramento em porcentagem#

Para acompanhar o uso relativo de forma simples:

lveinfo --user user_app --percentage --period=1day

Com a flag --percentage, qualquer métrica que se aproximar de 100% indica com clareza se a conta precisa de otimização ou de uma cota individual customizada.

Conclusão: lições práticas de estabilidade#

  1. Zero no LVE significa sem limites: Nunca confie em valores padrão sem auditar com lvectl list default.
  2. memory_limit do PHP não protege o host: O limite do php.ini restringe scripts isolados, mas não limita processos simultâneos, cron jobs ou rotinas de correio.
  3. Use strace -c para amostragem limpa: Em produção, profiling com strace -c entrega a volumetria de syscalls sem travar o processo com sinais invasivos de depuração.

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