PostgreSQL – Runbook Básico para Incidentes
Olá, pessoal!
Esse é meu primeiro artigo por aqui e resolvi começar falando de algo que todo DBA, cedo ou tarde, vai enfrentar: incidente em banco de dados.
Quando a gente começa a trabalhar com PostgreSQL em produção, tudo parece até tranquilo… até o dia em que a aplicação fica lenta, o time começa a cobrar, os alertas disparam e você se vê olhando para o banco pensando: “por onde eu começo?”.
Primeira coisa:
o problema é realmente o banco ou só estão jogando no seu colo?
Algumas perguntas rápidas:
O problema começou agora ou vem degradando?
É geral ou só uma aplicação?
Tem deploy recente?
Monitoramento acusa CPU, I/O, conexões ou locks?
Agora sim, bora pro banco.
Passo 1 – O PostgreSQL está vivo?
Conecta no banco e valida o básico:
SELECT now();Se conectou rápido, ótimo, se demorou, já é um sinal de alerta.
Passo 2 – Conexões demais costumam ser vilãs
Veja quantas conexões estão abertas:
SELECT count(*) FROM pg_stat_activity;Compare com:
SHOW max_connections;Se estiver perto do limite:, aplicação pode estar abrindo conexão demais, pool mal configurado, conexão presa sem encerrar
Passo 3 – Quem está rodando agora?
Essa é uma das queries mais importantes no incidente:
SELECT
pid,
usename,
application_name,
client_addr,
state,
wait_event_type,
wait_event,
now() - query_start AS runtime,
query
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY runtime DESC;Aqui você descobre: queries rodando há muito tempo, sessões travadas, quem está esperando lock, qual aplicação está causando impacto
Passo 4 – Locks: o assassino silencioso
Se tudo parece lento, locks são suspeitos fortes.
SELECT
pid,
usename,
wait_event_type,
wait_event,
query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock';Se aparecer muita coisa aqui: alguém segurou transação aberta, DDL rodando em horário errado, batch pesado sem commit
Passo 5 – Existe bloqueio em cascata?
Query clássica pra identificar quem bloqueia quem:
SELECT
blocked.pid AS blocked_pid,
blocked.query AS blocked_query,
blocking.pid AS blocking_pid,
blocking.query AS blocking_query
FROM pg_locks blocked_locks
JOIN pg_stat_activity blocked ON blocked.pid = blocked_locks.pid
JOIN pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.pid <> blocked_locks.pid
JOIN pg_stat_activity blocking ON blocking.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;Isso aqui costuma resolver metade dos incidentes.
Passo 6 – A sessão está rodando ou só esperando?
Nem tudo que está “ativo” está usando CPU.
Olhe para:
wait_event_type
wait_eventExemplos:
Lock → travamento
IO → gargalo de disco
ClientRead/Write → aplicação lenta pra consumir dados
Passo 7 – E o consumo geral do banco?
SELECT
numbackends,
xact_commit,
xact_rollback,
blks_read,
blks_hit,
tup_returned,
tup_fetched
FROM pg_stat_database
WHERE datname = current_database();Aqui você verifica: volume de transações, pressão de I/O padrão estranho de rollback
Passo 8 – Precisa agir ou só informar?
Nem todo incidente pede pg_terminate_backend. Às vezes a ação correta é: avisar que existe lock, pedir rollback da aplicação, aguardar batch finalizar, escalar para infra (I/O, storage, CPU)
Se precisar matar sessão, faça sabendo o impacto:
SELECT pg_terminate_backend(PID);
Antes de sair matando sessão no PostgreSQL e preciso ter o entendimento de que nem sempre se resolve com o classico “mata o PID aí que resolve”.
Aqui mora um erro clássico de quem está começando (e até de quem já tem estrada).
No PostgreSQL, nem todo PID é o problema.
Quando existe bloqueio, temos dois papéis claros:
- PID bloqueador → é quem segura o lock
- PID bloqueado → é quem está esperando o lock ser liberado
Se você matar o PID bloqueado, não resolve nada.
A aplicação vai simplesmente abrir outra conexão… e ela vai ficar bloqueada de novo. Quem realmente destrava o ambiente é o PID bloqueador.
Dicas finais de DBA que já passou por isso
Entenda o sintoma, não só a métrica.
Ter queries prontas salva minutos preciosos na sua analise.
Documente depois (pra não viver isso toda semana)
Conclusão
Quando a aplicação fica lenta e tudo vira caos, não é sobre saber tudo de PostgreSQL, é sobre saber por onde começar.
Esse runbook é exatamente isso:
um mapa pra atravessar o incidente com menos estresse e mais controle.
Se isso já te salvou (ou vai salvar), então valeu a pena escrever
