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_event

Exemplos:

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

Deixe um comentário