Pular para o conteúdo

Testar a restauração do backup

Intermediário12 min de leituradados

“Temos backup” é uma esperança. “Restauramos ontem em 38 minutos e conferimos os dados” é uma garantia. Este guia monta o ensaio, mede o que importa e o transforma em rotina automática.

Ensaie um cenário concreto, não “restaurar o banco”. Os três que valem a pena:

  • Perda total da instância — restaurar do backup mais recente.
  • Erro humano às 14h32 — restaurar para 14h31 (recuperação a ponto no tempo).
  • Perda da região — restaurar na região secundária.

Anote o alvo antes de começar: RTO (quanto tempo você pode levar) e RPO (quanto dado pode perder). O ensaio existe para dizer se os dois são reais.

Nunca ensaie por cima de produção, e nem em um ambiente que produção consulte.

Janela do terminal
# Postgres: restauração lógica em instância descartável
createdb -h "$HOST_TESTE" ensaio_$(date +%F)
pg_restore --clean --if-exists --no-owner --jobs 4 \
--dbname "postgresql://$HOST_TESTE/ensaio_$(date +%F)" backups/loja-mais-recente.dump
Janela do terminal
# RDS: PITR cria uma instância nova, sem tocar na original
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier loja-prod \
--target-db-instance-identifier ensaio-restore \
--restore-time 2026-09-03T17:31:00Z \
--db-subnet-group-name privado --no-publicly-accessible

Cronometre desde o primeiro comando — o relógio do RTO já começou.

Comando que retorna zero não significa base utilizável. Verifique conteúdo:

Janela do terminal
URL="postgresql://$HOST_TESTE/ensaio_$(date +%F)"
# a base tem as tabelas esperadas?
psql "$URL" -tAc "SELECT count(*) FROM information_schema.tables WHERE table_schema='public'"
# o dado mais recente — este número é o seu RPO real
psql "$URL" -tAc "SELECT max(criado_em) FROM pedidos"
# volumes por tabela crítica, comparados com a ordem de grandeza esperada
psql "$URL" -tAc "SELECT 'pedidos', count(*) FROM pedidos
UNION ALL SELECT 'clientes', count(*) FROM clientes"
# integridade referencial e objetos que costumam faltar
psql "$URL" -tAc "SELECT count(*) FROM pedidos p
LEFT JOIN clientes c ON c.id = p.cliente_id WHERE c.id IS NULL"
psql "$URL" -tAc "SELECT count(*) FROM pg_indexes WHERE schemaname='public'"

O que costuma não vir no backup e quebrar a restauração real: sequências fora de sincronia, extensões, funções, permissões de usuário, e configurações do servidor. Confira todos.

Uma verificação a mais, quando possível: aponte uma cópia da aplicação para a base restaurada e execute o fluxo principal. É o teste que prova utilidade, não apenas presença.

Ensaio 2026-09-04 — Postgres loja (backup lógico diário)
Início: 09h02 Fim: 09h40 RTO real: 38 min (alvo: 60 min ✅)
Dado mais recente: 2026-09-04 02:00 RPO real: 7h02 (alvo: 24h ✅)
Verificações: 12 tabelas, contagens dentro do esperado, 0 órfãos, 34 índices
Achados: sequências precisaram de setval manual (+6 min); documentado no runbook
Executado por: @bruno (primeira vez sozinho)

Registre também os achados — eles são o produto real do ensaio. RTO estimado quase nunca é o RTO medido.

Ensaio manual acontece duas vezes e é esquecido. Transforme em job semanal:

#!/usr/bin/env bash
set -euo pipefail
inicio=$(date +%s)
ULTIMO=$(ls -t backups/*.dump | head -1)
pg_restore --clean --if-exists --dbname "$URL_TESTE" "$ULTIMO"
linhas=$(psql "$URL_TESTE" -tAc "SELECT count(*) FROM pedidos")
recente=$(psql "$URL_TESTE" -tAc "SELECT extract(epoch from now() - max(criado_em)) FROM pedidos")
[ "$linhas" -gt 0 ] || { echo "base vazia"; exit 1; }
duracao=$(( $(date +%s) - inicio ))
# publique como métrica: estes dois números são o seu RTO e RPO reais
cat <<EOF | curl --data-binary @- http://pushgateway:9091/metrics/job/ensaio_restore
restore_duracao_segundos $duracao
restore_atraso_dado_segundos $recente
EOF
# alerte quando o ensaio parar de rodar ou passar do alvo
time() - restore_ultimo_sucesso_timestamp > 8 * 24 * 3600
restore_duracao_segundos > 3600

E limpe o ambiente de ensaio ao final — restauração esquecida ligada é uma das linhas mais comuns de gasto inesperado.

Automatizado prova o mecanismo. Uma vez por ano, exercite o procedimento: alguém que não é a pessoa de sempre restaura seguindo apenas o runbook, sem ajuda. Os achados aí são quase sempre acesso que falta, documento desatualizado e dependência esquecida.

Sintoma Causa provável
pg_restore falha no meio Dump truncado, ou versão do servidor incompatível
Base restaurada sem dados recentes O backup em si está atrasado — verifique o job
Aplicação não conecta na cópia Faltaram usuários e permissões no backup lógico
Sequências reiniciando ids setval não aplicado; adicione ao procedimento
RTO muito acima do alvo Backup lógico em base grande — considere PITR/snapshot
Snapshot restaura inconsistente Snapshot de volume sem quiesce; use o backup do banco
  • Cenário e alvos de RTO/RPO escritos.
  • Restauração feita em ambiente isolado.
  • Integridade verificada por conteúdo, não por exit code.
  • Objetos auxiliares conferidos (sequências, extensões, permissões, índices).
  • Tempo e atraso do dado registrados como métrica.
  • Ensaio automatizado com alerta de ausência e de estouro do alvo.
  • Ensaio anual com pessoas, seguindo apenas o runbook.
  • Ambiente de ensaio destruído ao final.