Pular para o conteúdo

Backup que funciona

Intermediário16 min de leituradados

Backup não testado não é backup: é uma esperança com custo de armazenamento. A pergunta que importa não é “temos backup?” — é “quando foi a última vez que restauramos e quanto tempo levou?”. Times que respondem à segunda com uma data e um número dormem melhor.

Os modos de falha são sempre os mesmos: o job estava falhando há semanas e ninguém viu; o backup existia mas era de uma tabela só; a restauração levaria 14 horas e o negócio aguentava 2; o ransomware criptografou também o destino dos backups.

  • RPO (Recovery Point Objective): quanto dado você aceita perder, medido em tempo. Backup a cada 24h = RPO de até 24h.
  • RTO (Recovery Time Objective): quanto tempo o serviço pode ficar fora até estar restaurado.

Os dois são decisões de negócio, não de infraestrutura — e precisam ser negociados por sistema, porque “zero e zero” custa mais que a empresa inteira. A conversa útil:

Se perdermos as últimas 4 horas de pedidos, o que acontece? Dá para reconstruir a partir de outro sistema? E se o sistema ficar 6 horas fora, quanto custa?

Anote a resposta, transforme em política (frequência de backup e arquitetura de restauração) e valide com o teste de restauração. RPO no papel sem ensaio é ficção.

A regra clássica continua válida: 3 cópias dos dados, em 2 mídias ou tecnologias diferentes, com 1 fora do local principal. Na nuvem, traduzindo:

  • Cópia 1: o próprio banco, com replicação.
  • Cópia 2: snapshot automatizado na mesma região.
  • Cópia 3: backup em outra região ou outra conta/projeto, com credencial separada.

O acréscimo moderno é a imutabilidade. Ransomware e erro humano apagam o que a credencial da produção alcança — inclusive backups.

Janela do terminal
# S3 Object Lock: nem o administrador apaga antes do prazo
aws s3api put-object-retention --bucket empresa-backups --key pg/2026-09-04.dump \
--retention '{"Mode":"COMPLIANCE","RetainUntilDate":"2026-12-04T00:00:00Z"}'

Some a isso: conta separada para os backups, criptografia com chave que a produção não controla e alerta em qualquer tentativa de exclusão.

Lógico (pg_dump, mysqldump) Físico (snapshot, PITR)
Conteúdo SQL/dados, portátil Arquivos do banco, ligado à versão
Restaurar parte Fácil (uma tabela) Difícil
Velocidade em base grande Lenta Rápida
Mudar de versão/servidor Fácil Limitado
Ponto no tempo Não Sim, com WAL/binlog

Use os dois. O físico com PITR (recuperação a ponto no tempo) é o que resolve o caso real mais comum — “alguém rodou um DELETE sem WHERE às 14h32” — porque permite restaurar para 14h31.

Janela do terminal
# lógico, com verificação de integridade do arquivo gerado
pg_dump --format=custom --compress=9 --file=loja.dump "$DATABASE_URL"
pg_restore --list loja.dump > /dev/null && echo "dump íntegro"

Snapshot de volume, sozinho, não garante consistência transacional para banco em execução. Use o mecanismo de backup do próprio banco, ou faça o snapshot com quiesce.

É a única parte inegociável desta página. Automatize e agende:

#!/usr/bin/env bash
set -euo pipefail
# 1. pega o backup mais recente e restaura em instância descartável
pg_restore --clean --if-exists --dbname="$URL_TESTE" "$(ls -t backups/*.dump | head -1)"
# 2. verifica que o dado faz sentido, não só que o comando saiu com 0
psql "$URL_TESTE" -tAc "SELECT count(*) FROM pedidos WHERE criado_em > now() - interval '1 day'"
psql "$URL_TESTE" -tAc "SELECT max(criado_em) FROM pedidos" # RPO real, medido
# 3. publica a duração como métrica — este número é o seu RTO real

O que medir e guardar em cada ensaio: tempo total (é o seu RTO de verdade), atraso do dado mais recente (é o seu RPO de verdade) e verificações de conteúdo que provam que a base está utilizável. Trimestral é o mínimo; mensal é melhor; automatizado é o que sobrevive.

Faça pelo menos uma vez por ano o ensaio completo com pessoas: quem restaura, com qual acesso, seguindo qual documento, sem a pessoa que sempre faz — que é justamente quem pode estar de férias no dia.

  • Alerta quando o job não roda (ausência de sinal, não só erro).
  • Alerta quando o tamanho do backup varia muito — uma queda brusca costuma ser dump parcial.
  • Painel com idade do backup mais recente por sistema.
  • Verificação de restauração como check recorrente, com resultado visível.
time() - backup_ultimo_sucesso_timestamp{sistema="postgres-loja"} > 26 * 3600

E não esqueça do que não é banco: configuração de infraestrutura (que vive no Git), segredos do cofre, objetos em buckets, e o próprio repositório — provedores de Git também falham e a conta pode ser perdida.

Próximo passo: reduza a chance de precisar do backup com Alta disponibilidade em banco de dados. O ensaio prático está em Testar restore.