Linux OOM Killer Tuning para VPS: um guia prático

12 min de leitura - 8 de junho de 2026

hero section cover
Índice
  • Ajuste do OOM killer do Linux para VPS
  • Como o OOM killer escolhe uma vítima
  • Detetar a pressão de memória antes da falha
  • Proteger processos críticos com oom_score_adj
  • Limitar a memória com cgroups e systemd
  • Ler os registos após um evento OOM
  • Conclusão
Partilhar

Ajuste o Linux OOM killer no seu VPS para proteger bases de dados e SSH, limitar processos em fuga com cgroups e impedir que o serviço errado seja morto.

Ajuste do OOM killer do Linux para VPS

O Linux OOM killer é o último recurso do kernel quando a memória se esgota: ele seleciona um processo e encerra-o para manter o sistema ativo. Num VPS, onde a RAM é limitada e não há para onde recorrer, a escolha padrão é frequentemente a errada. A sua base de dados é encerrada, um processo de execução prolongada sobrevive e fica com a tarefa de descobrir porquê. Este guia aborda como o OOM killer pontua os processos, como direcionar essa pontuação para os seus serviços críticos e como utilizar cgroups para que um único processo descontrolado não consiga derrubar o resto do sistema consigo.


 

Como o OOM killer escolhe uma vítima

Quando o kernel não consegue recuperar memória suficiente através da evicção da cache de páginas ou do swap, invoca o OOM killer. Cada processo tem uma oom_score entre 0 e 1000, derivado principalmente do seu Resident Set Size (RSS) e da utilização do swap. O processo com a pontuação mais alta recebe um SIGKILL.

O RSS domina o cálculo, razão pela qual o kill recai quase sempre sobre o maior consumidor de memória. Frequentemente, trata-se da sua base de dados, do seu servidor de aplicações ou de qualquer processo de longa duração que esteja a realizar o trabalho mais útil. O processo que realmente desencadeou a alocação, o «invoker», raramente é aquele que é terminado.

Existem dois tipos de eventos OOM que deve distinguir:

  • OOM global: o host (ou o seu VPS como um todo) está sem RAM e swap. O kernel analisa todos os processos e encerra aquele com a pontuação mais alta.
  • OOM de cgroup: um cgroup específico atingiu o seu limite de memória. O kernel apenas encerra processos dentro desse cgroup, mesmo que o resto do sistema tenha memória disponível.

Se tiver configurado limites de unidades do systemd ou estiver a executar contentores, a maioria dos seus eventos OOM serão OOMs de cgroup. Isso é bom: o raio de impacto é contido.

Detetar a pressão de memória antes da falha

Os eventos OOM quase nunca são repentinos. Normalmente, há primeiro um período de pressão crescente, e o objetivo da monitorização é detetá-la dentro desse período.

free -h fornece-lhe a vista do sistema. A coluna que importa é available, não free: ela representa o cache de páginas recuperável e reflete o que pode realmente alocar sem troca. Mantenha MemAvailable acima de cerca de 10 a 15 por cento MemTotal no pico de carga.

Para atribuição por processo, ordene por RSS:

ps aux --sort=-%mem | head -10

Ou use htop e ordene por RES. Os valores que vê aqui alimentam diretamente a pontuação do kernel, pelo que as entradas no topo são os alvos mais prováveis de OOM.

Nos kernels 4.20 e mais recentes, a Informação de Estagnação por Pressão é o sistema de alerta precoce que vale a pena integrar na monitorização:

cat /proc/pressure/memory

O some avg10 figura representa a percentagem de tempo em que pelo menos uma tarefa ficou bloqueada à espera de memória nos últimos dez segundos. Valores abaixo de 5% são aceitáveis. Valores sustentados acima de 10% significam que o sistema está a perder tempo real bloqueado na recuperação de memória, e é provável que ocorra um encerramento por OOM.

O swap thrashing aparece em vmstat 1 como um valor diferente de zero si e so colunas que se mantêm ao longo do tempo. Uma pequena quantidade de swap residente é inofensiva. O swap-in e o swap-out constantes não o são.

Proteger processos críticos com oom_score_adj

A pontuação calculada pelo kernel pode ser ajustada por processo através de oom_score_adj, numa escala de -1000 (imune) a +1000 (matar-me primeiro). O ajuste é adicionado diretamente à pontuação final.

Para uma alteração pontual num processo em execução:

echo -500 | sudo tee /proc/$(pidof sshd)/oom_score_adj

Para qualquer coisa que queira manter após reinicializações, defina-a na unidade systemd. Esse é o local certo para o sshd, a sua base de dados e qualquer outra coisa que não possa dar-se ao luxo de perder:

[Service]
OOMScoreAdjust=-900

Padrões sensatos para começar:

  • sshd: -1000. Se perder o acesso remoto durante uma crise de memória, a recuperação torna-se muito mais difícil.
  • MySQL, PostgreSQL, Redis: -800 a -900. Proteção robusta sem torná-los completamente intocáveis numa situação verdadeiramente catastrófica.
  • Processos de aplicações, tarefas em lote, tarefas cron: +100 a +500. Estes são os processos que prefere ver encerrados em vez do seu banco de dados.

Não defina tudo para -1000. Se nada puder ser encerrado, o kernel acabará por entrar em pânico ou bloquear, o que é pior.

Limitar a memória com cgroups e systemd

Ajustar as pontuações influencia quem é encerrado. Os cgroups influenciam se o encerramento global chega a ocorrer. Ao atribuir a cada serviço um limite máximo rígido, empurra-se as falhas de memória para um único cgroup, em vez de permitir que um processo esgote todo o VPS.

Num ficheiro de unidade do systemd:

[Service]
MemoryHigh=400M
MemoryMax=512M
OOMPolicy=stop
Restart=on-failure
RestartSec=5s

MemoryHigh é um limitador flexível: o kernel recupera agressivamente páginas do cgroup acima deste ponto, mas não encerra nada. MemoryMax é o limite máximo rígido. Se o cgroup tentar alocar além desse limite, o kernel encerra um processo dentro do cgroup. Com Restart=on-failure o serviço volta a arrancar imediatamente.

No cgroup v2 (Ubuntu 22.04 e versões posteriores, Debian recente, RHEL 9), memory.oom.group encerra todos os processos no cgroup em conjunto, em vez de deixar processos órfãos para trás. Útil para serviços multiprocessos como pools PHP-FPM, onde um grupo parcialmente encerrado apresentará comportamento irregular.

Algumas notas específicas para aplicações que vale a pena aplicar:

  • PHP-FPM: defina pm = ondemand em instâncias VPS pequenas e defina pm.max_children em relação à média de RSS por trabalhador, e não ao valor padrão. Um pool dimensionado para 4 GB de margem em um VPS de 2 GB entrará em OOM na primeira vez que ficar cheio.
  • Node.js: limite a pilha do V8 com --max-old-space-size=512 (em MB). Sem isso, o Node continuará a crescer até que o kernel intervenha.
  • MySQL e PostgreSQL: innodb_buffer_pool_size e shared_buffers devem deixar espaço livre para o cache de páginas do SO, a memória de conexão e quaisquer outros utilizadores na máquina. Os valores padrão pressupõem um servidor dedicado.

Ler os registos após um evento OOM

Quando o OOM killer é acionado, o kernel descarrega um relatório detalhado no buffer circular. Recupere-o com:

dmesg -T | grep -iE 'killed process|out of memory'
journalctl -k --grep='Out of memory'

O bloco a ler com atenção começa com o invocador e termina com a vítima. O kernel imprime uma lista completa de tarefas com o RSS de cada processo, a utilização de swap e o oom_score_adj. Vale a pena verificar três coisas:

  • A restrição. CONSTRAINT_NONE significa um OOM global, CONSTRAINT_MEMCG significa que um cgroup atingiu o seu limite. A correção é diferente em cada caso.
  • Free swap. Se for este o caso 0kB, tanto a RAM como o swap foram esgotados. Adicione swap, aumente MemoryMax no processo culpado ou reduza a concorrência.
  • A pontuação da vítima em comparação com todas as outras. Se a pontuação da vítima não for muito superior à dos processos seguintes, os teus oom_score_adj valores não estão a funcionar suficientemente bem. Aumente a diferença.

Especificamente para OOMs de cgroup, o contador de kill reside memory.events dentro do cgroup:

cat /sys/fs/cgroup/system.slice/mysql.service/memory.events

Um aumento oom_kill significa que o serviço está a atingir repetidamente o seu limite. Isso é um sinal para aumentar MemoryMax, analisar a carga de trabalho ou mudar o serviço para um plano superior, em vez de continuar a reiniciá-lo em loop.

Conclusão

Ajustar o OOM killer não significa fazê-lo desaparecer. Trata-se de controlar qual o processo que paga o preço quando a memória se esgota e de reduzir o raio de impacto quando isso acontece. O padrão que se mantém em produção:

  • Proteja com pontuação os serviços que não pode dar-se ao luxo de perder, especialmente o sshd e as suas bases de dados.
  • Limite tudo o resto com MemoryMax numa unidade systemd para que uma única falha resulte num único reinício, e não numa interrupção do serviço.
  • Fique atento ao PSI e MemAvailable em vez de esperar dmesg que lhe conte a história depois.
  • Deixe 15 a 20 por cento da RAM como margem de manobra. O ajuste não consegue compensar um VPS que é simplesmente demasiado pequeno para a carga de trabalho.

Se a sua pressão de memória for estrutural em vez de configurável, precisa de mais RAM ou de armazenamento mais rápido com swap. Os planos VPS da FDC Servers funcionam em AMD EPYC com armazenamento NVMe, o que mantém as leituras com swap suficientemente rápidas para que picos de memória curtos não se transformem em encerramentos.

Blogue

Em destaque esta semana

Mais artigos
Linux OOM Killer Tuning para VPS: um guia prático

Linux OOM Killer Tuning para VPS: um guia prático

Ajuste o Linux OOM killer no seu VPS para proteger bases de dados e SSH, limitar processos em fuga com cgroups e impedir que o serviço errado seja morto.

12 min de leitura - 8 de junho de 2026

Controlo de tráfego Linux (tc): um guia prático

12 min de leitura - 5 de junho de 2026

Mais artigos