10 abr 2026 9 min

322 milhões de dead tuples depois: anatomia de um incidente PostgreSQL

Um post-mortem honesto sobre bloat, wraparound e as decisões de tuning que deveriam ter sido tomadas um ano antes.

Este é um post-mortem honesto. Não o tipo higienizado que vira slide de conferência, mas o relato de um incidente que começou meses antes de acontecer — em decisões de tuning que adiamos porque “estava funcionando”.

O sintoma não é o problema

O alerta que disparou foi latência de query. O problema real eram 322 milhões de dead tuples acumuladas: versões de linha que o VACUUM não conseguiu recolher no ritmo em que criávamos. O banco estava carregando um cemitério e pagando pedágio em cada leitura.

A conta que o autovacuum não fecha sozinho

O autovacuum é excelente por padrão — até o dia em que sua taxa de escrita passa a configuração default de longe. Nós tínhamos ultrapassado esse ponto havia meses sem ajustar os thresholds. A ameaça de transaction ID wraparound deixou de ser teoria de manual e virou um relógio real no painel.

O que deveria ter sido feito um ano antes

Monitorar bloat como métrica de primeira classe, não como curiosidade. Ajustar autovacuum_vacuum_cost_limit e os thresholds para a nossa taxa de escrita real, não para a de um banco de brinquedo. E, sobretudo, tratar manutenção de banco como trabalho contínuo — não como algo que se faz quando o gráfico já está vermelho. O incidente foi caro; a lição, mais barata do que teria sido a prevenção.

← todos os insights