O que é o OOM Killer do Linux
Se você já administrou um servidor Linux com PostgreSQL em produção, talvez já tenha encontrado uma mensagem assustadora nos logs do sistema: "Out of Memory: Kill process". Isso e o OOM Killer (Out Of Memory Killer), um mecanismo do kernel Linux que entra em ação quando a memoria RAM esgota. Ele escolhe um processo para matar e liberar memoria, e muitas vezes esse processo e exatamente o seu PostgreSQL.
O OOM Killer não e um bug. Ele existe para salvar o sistema operacional quando não ha mais memoria disponível. O problema e que ele pode derrubar seu banco de dados no pior momento possível, causando perda de conexões, rollback de transações em andamento e tempo de inatividade não planejado. Para ambientes de produção, isso é inaceitável.
O tema voltou a ganhar atenção recentemente com um post da Ubicloud explicando por que a empresa adotou o overcommit estrito em todos os seus hosts com PostgreSQL. A discussão tocou em um ponto crítico que muitos desenvolvedores ignoram até ser tarde demais.
Como funciona o overcommit de memoria no Linux
Para entender o problema, e preciso saber como o Linux gerência memoria. Por padrão, o kernel usa uma estratégia chamada overcommit otimista: ele permite que processos alocem mais memoria do que esta fisicamente disponível, apostando que nem todos vao usar tudo ao mesmo tempo. Isso e útil para linguagens como Python e Ruby, que fazem muitos fork() e raramente usam toda a memoria alocada.
O PostgreSQL, porém, tem um comportamento diferente. Quando o processo principal faz fork() para criar um worker, o Linux anota que aquele filho pode precisar de tanta memoria quanto o pai. Se o sistema estiver com overcommit e muitos workers forem criados, o kernel pode aceitar alocações que nunca conseguira cumprir. Quando a conta chegar, o OOM Killer entra em cena.
Existem três modos de overcommit no Linux, controlados pelo parâmetro /proc/sys/vm/overcommit_memory: 0 (heurística padrão), 1 (sempre permite, sem limite) e 2 (estrito, não permite alocar mais do que um percentual fixo da RAM + swap). O modo 2 e o que a Ubicloud e outras empresas que operam PostgreSQL em larga escala recomendam.
Principais riscos do overcommit otimista com PostgreSQL
O maior risco e o processo principal do PostgreSQL ser morto pelo OOM Killer. Quando isso acontece, todos os processos filhos (workers de conexão, autovacuum, WAL writer) são encerrados junto. O banco fica indisponível até ser reiniciado manualmente ou pelo supervisor.
Além do tempo de inatividade, ha risco de corrupção de dados em cenários onde uma transação estava sendo gravada no momento do kill. O PostgreSQL tem mecanismos de recuperação via WAL (Write-Ahead Log), mas o processo de recovery leva tempo e não e garantido em todos os cenários de crash.
Outro risco e o OOM Killer matar processos errados. Ele usa um algoritmo de pontuação (oom_score) que nem sempre escolhe o processo menos importante. Em servidores com múltiplos serviços, ele pode matar o PostgreSQL mesmo que outros processos sejam menos críticos.
Como configurar o overcommit estrito no Linux
A configuração e simples e pode ser feita em minutos. Primeiro, verifique o valor atual:
cat /proc/sys/vm/overcommit_memory
Para ativar o overcommit estrito, execute como root:
sysctl -w vm.overcommit_memory=2sysctl -w vm.overcommit_ratio=80
O overcommit_ratio define quanto da RAM (em percentual) pode ser comprometido além do swap. Um valor de 80 e conservador e seguro para a maioria dos servidores dedicados ao PostgreSQL. Para tornar a configuração permanente após reboot, adicione ao arquivo /etc/sysctl.conf:
vm.overcommit_memory = 2
vm.overcommit_ratio = 80
Em seguida, aplique sem precisar reiniciar: sysctl -p. Após isso, o kernel vai recusar alocações de memoria que excedam o limite configurado, lançando um erro no processo que tentou alocar, em vez de aceitar e depois matar processos aleatoriamente.
Exemplo prático: antes e depois
Imagine um servidor com 16 GB de RAM rodando PostgreSQL com shared_buffers = 4GB e max_connections = 200. Cada conexão pode usar até 5-10 MB de memoria de trabalho (work_mem). No pico, o servidor pode tentar usar muito mais memoria do que tem disponível.
Com overcommit otimista (modo 0), o Linux aceita todas as alocações. Quando a memoria acaba, o OOM Killer escolhe vitimas. Com overcommit estrito (modo 2 e ratio 80), o limite máximo de memoria comprometida e 0.80 * 16GB + swap. Se o PostgreSQL tentar passar desse limite ao criar conexões, os novos processos recebem um erro de alocação imediatamente, o cliente recebe uma mensagem de erro de conexão, e o banco principal continua rodando sem ser morto.
Esse e o trade-off: com overcommit estrito, você pode ter falhas de conexão em picos de carga, mas o banco não cai. Com overcommit otimista, o banco pode ser morto silenciosamente em qualquer momento.
Comparação com alternativas
Além do overcommit estrito, existem outras abordagens para proteger o PostgreSQL do OOM Killer. A mais usada e ajustar o oom_score_adj do processo para -1000, o que o torna imune ao OOM Killer:
echo -1000 > /proc/$(pidof postgres)/oom_score_adj
O problema e que isso apenas empurra o problema para outros processos. O OOM Killer vai matar outra coisa, que pode ser igualmente crítica. Outra alternativa e usar cgroups para limitar a memoria que o PostgreSQL pode usar, mas a configuração e mais complexa e exige conhecimento de containers ou systemd.
A abordagem do overcommit estrito e preferida porque resolve o problema na raiz: o sistema operacional para de prometer o que não pode cumprir. Ela também é a mais simples de configurar e a que tem menos efeitos colaterais inesperados.
Pontos positivos e limitações
O overcommit estrito tem vantagens claras: elimina o risco de o OOM Killer matar o PostgreSQL, torna o comportamento de memoria previsível e facilita o dimensionamento do servidor. E a abordagem adotada por empresas como Ubicloud, Amazon RDS e outros provedores de banco de dados gerenciado.
As limitações existem. Ferramentas que fazem muitos fork() podem falhar em servidores com overcommit estrito se a memoria disponível for insuficiente. Linguagens como Ruby on Rails ou Python com Celery, se rodando no mesmo servidor, podem se comportar de forma inesperada. Por isso, a recomendação e usar overcommit estrito em servidores dedicados ao PostgreSQL.
Também é importante dimensionar bem o servidor antes de ativar o overcommit estrito. Se você tiver poucos recursos e muitas conexões, vai começar a ver erros de alocação mais cedo do que gostaria. Ferramentas como PgBouncer para pooling de conexões ajudam a reduzir a pressão de memoria.
Casos de uso reais
Startups com PostgreSQL em VPS pequena: Servidores com 4-8 GB de RAM são os mais vulneráveis ao OOM Killer. Com picos de tráfego, o banco pode cair e derrubar toda a aplicação. O overcommit estrito mais PgBouncer e a combinação mais eficaz nesses casos.
Bancos de dados de analytics com queries pesadas: Queries de relatório podem consumir muito work_mem temporariamente. Com overcommit otimista, o risco de OOM e alto. Com overcommit estrito, a query falha graciosamente em vez de derrubar o banco.
Servidores multi-tenant: Quando o mesmo servidor roda o PostgreSQL e outros serviços (Nginx, Redis, worker), o OOM Killer pode tomar decisões ruins. O overcommit estrito força o planejamento explicitico de recursos.
Ambientes de alta disponibilidade: Em clusters com replicação, um OOM no primário provoca failover. Com overcommit estrito, a chance de OOM inesperado e muito menor, reduzindo failovers desnecessários.
Dicas e boas práticas
Antes de ativar o overcommit estrito, calcule o uso real de memoria do seu PostgreSQL. A formula básica e: shared_buffers + (max_connections * work_mem) + maintenance_work_mem + autovacuum_work_mem. Isso da uma estimativa do máximo que o banco pode usar.
Use PgBouncer para reduzir max_connections no PostgreSQL. Com pooling, você pode ter 1000 conexões de aplicação e apenas 50-100 conexões reais no banco, reduzindo drasticamente o consumo de memoria por conexão.
Monitore o arquivo /var/log/syslog ou dmesg para detectar mensagens do OOM Killer. Se você encontrar entradas com "Out of Memory: Kill process", o problema já aconteceu em produção. Configure alertas no seu sistema de monitoramento para essas mensagens.
Vale a pena ativar o overcommit estrito?
Sim, para qualquer servidor dedicado ao PostgreSQL em produção. A configuração leva menos de 5 minutos e pode evitar incidentes críticos. O único cenário em que o overcommit estrito pode ser problemativo e em servidores compartilhados com aplicações que dependem muito de fork(), como processos Ruby ou Python com muitos workers.
O próximo passo e verificar o overcommit_memory do seu servidor agora mesmo com cat /proc/sys/vm/overcommit_memory. Se retornar 0 ou 1, considere migrar para o modo 2. Combine isso com PgBouncer para conexão pooling e monitoramento de logs do kernel, e seu PostgreSQL vai sobreviver a picos de carga sem surpresas desagradáveis.