O desenvolvimento remoto via SSH utilizando editores modernos tornou-se padrão no dia a dia. No entanto, ferramentas de autocompletar e análise estática executam processos pesados no servidor remoto. Um dos binários que mais frequentemente gera picos de recursos é o devsense.php.ls (o Language Server da extensão PHP da DEVSENSE).
Neste artigo, compartilho o diagnóstico em nível de sistema operacional e as duas frentes aplicadas para neutralizar o impacto desse processo: ajustes no settings.json do editor e controle de recursos no kernel Linux.
1. O problema: gargalos de CPU, memória e i/o#
O devsense.php.ls não é um script PHP interpretado pontualmente. Trata-se de um binário compilado que roda como processo persistente (sidecar) comunicando-se via JSON-RPC através do Language Server Protocol (LSP).
Em bases de código grandes (como Laravel ou Magento), ele pode apresentar os seguintes gargalos:
- Picos de CPU e Troca de Contexto: A varredura de árvores sintáticas (AST) eleva drasticamente o context-switch no processador.
- Pressão de Memória (RSS): A tabela de símbolos e índices de tipagem aumentam a ocupação da memória RAM.
- Esgotamento de File Watchers (
inotify): Ao atingir o limite de observadores do kernel, o processo degrada para polling contínuo com chamadas manuais ao disco. - Processos Órfãos: Conexões SSH encerradas abruptamente podem deixar o binário rodando em segundo plano sem cliente ativo.
2. Diagnóstico no terminal com ferramentas de baixo nível#
Para inspecionar o comportamento real do processo:
1. Rastreando chamadas de sistema com strace#
Para checar se o processo está em loop infinito varrendo pastas pesadas (vendor, node_modules):
strace -p <PID> -e trace=file,desc
Para detectar o comportamento de polling excessivo (enxurrada de chamadas lstat):
strace -p <PID> -e trace=lstat | head -n 100
Se o terminal exibir milhares de chamadas lstat contínuas, o processo excedeu o limite do inotify e está varrendo o disco manualmente.
2. Inspecionando memória com pmap#
Para auditar a alocação de Heap e bibliotecas mapeadas:
pmap -x <PID> | sort -n -k3
3. Checando a comunicação IPC e sockets#
Como o Language Server normalmente se comunica via stdio (JSON-RPC através de pipes herdados do editor remoto), ele raramente abre portas de rede convencionais. Inspecione descritores de arquivo, pipes e eventuais sockets locais:
# Listar descritores de arquivo e pipes IPC do processo
ls -l /proc/<PID>/fd
# Inspecionar sockets de rede ou UNIX abertos pelo processo
lsof -p <PID> | grep -E 'unix|FIFO|IPv[46]'
# Listar sockets UNIX locais ativos
ss -xap | grep <PID>
3. Solução em duas frentes#
A contenção foi implementada em duas camadas complementares:
Frente 1: Restringindo o escopo do language server no settings.json#
A forma mais eficiente de evitar varreduras globais é limitar a análise apenas aos arquivos abertos e instruir tanto o LSP quanto o VS Code a ignorar diretórios pesados:
{
"php.problems.scope": "opened",
"php.analysis.extractTypes": false,
"php.stubs.load": false,
"php.inlayHints.enabled": false,
"files.watcherExclude": {
"**/vendor/**": true,
"**/node_modules/**": true,
"**/temp/**": true,
"**/storage/**": true
}
}
php.problems.scope: "opened": Analisa somente os arquivos com abas ativas no editor, desativando o worker global na raiz do projeto.files.watcherExclude: Impede que o sistema de watch do editor e do language server monitore pastas de terceiros e cache.- Desativação de Type Analysis, Stubs e Inlay Hints: Reduz substancialmente a alocação inicial de memória Heap e o processamento em segundo plano.
Frente 2: Contenção de recursos no Linux#
Para evitar que sessões concorrentes saturem a máquina:
1. Prioridade de i/o e CPU com ionice e renice#
# Prioridade de I/O para Idle (Classe 3)
ionice -c 3 -p <PID>
# Menor prioridade de agendamento de CPU (Nice +19)
renice +19 -p <PID>
2. Limitação de memória com Cgroups#
Para evitar que o processo cause OOM (Out of Memory) e derrube outros serviços:
# Cgroups v2 (padrão em distribuições modernas como Ubuntu 22.04+, Debian 12+, RHEL 9+)
sudo mkdir -p /sys/fs/cgroup/devsense_limit
echo 536870912 | sudo tee /sys/fs/cgroup/devsense_limit/memory.max
echo <PID> | sudo tee /sys/fs/cgroup/devsense_limit/cgroup.procs
# Cgroups v1 (ambientes legados com libcgroup-tools)
sudo cgcreate -g memory:devsense_limit
echo 512M | sudo tee /sys/fs/cgroup/memory/devsense_limit/memory.limit_in_bytes
sudo cgclassify -g memory:devsense_limit <PID>
3. Aumentar o limite de observadores do inotify#
Para evitar a degradação para loops de lstat:
# Aplicação imediata
sudo sysctl -w fs.inotify.max_user_watches=524288
# Configuração persistente (sobrevive a reboots)
echo "fs.inotify.max_user_watches = 524288" | sudo tee /etc/sysctl.d/90-inotify.conf
sudo sysctl --system
Referência de métricas para monitoramento#
| Métrica | Comportamento Saudável | Sinal de Alerta |
|---|---|---|
| Resident Set Size (RSS) | 200 MB a 1 GB (estável) | Crescimento linear contínuo (Memory Leak) |
| File Descriptors | Alto apenas na inicialização | Próximo do limite configurado (ulimit -n) |
| Syscalls | futex, epoll_wait, read | Loops contínuos de stat e lstat |
Boas práticas para controlar language servers no Linux#
- Exclua diretórios de dependências: Sempre adicione
vendor/enode_modules/nas regras de exclusão de indexação do LSP. - Ajuste o inotify do kernel de forma persistente: Manter
max_user_watchesalto evita que ferramentas de desenvolvimento degradem para leitura contínua de disco. - Use cgroups em servidores multiusuário: Limitar o consumo de memória de processos remotos garante a estabilidade dos serviços essenciais do host.
Conclusão#
Neste artigo compartilhei as duas frentes que usei para domar o devsense.php.ls: restringir o escopo de análise no editor e conter o processo no kernel — com strace e pmap para confirmar o sintoma antes de agir. A combinação de exclusão de diretórios pesados, cgroup com limite de memória e inotify folgado manteve o host estável com vários desenvolvedores conectados simultaneamente.
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