CTO no Integrar Plus • Publicado em 19 de September de 2026
Ter um arquivo de duzentos gigabytes salvo em um bucket de armazenamento não significa que sua empresa possui backup. Significa apenas que você gasta dinheiro guardando bytes que podem falhar no momento exato em que a produção desaparecer.
A maioria dos times de infraestrutura só descobre a diferença prática entre fazer cópia de segurança e recuperar dados durante um incidente com o serviço fora do ar. O debate técnico costuma se dividir em dois grupos barulhentos.
De um lado estão os defensores do minimalismo cego: um script rápido no cron disparando pg_dump toda madrugada, compactando o arquivo com gzip e enviando o tarball para a nuvem. O argumento dessa turma é a portabilidade, a simplicidade de execução e o fato de que qualquer desenvolvedor júnior sabe rodar um comando para cuspir o esquema.
Do outro lado estão os puristas corporativos que desprezam qualquer solução que não utilize Barman ou pgBackRest com arquivamento contínuo de Write-Ahead Logs (WAL) e recuperação ponto a ponto a cada segundo. Para esse grupo, quem usa dump lógico está brincando de tecnologia e deveria ser banido de ambientes de produção.
A maioria dos defensores do pg_dump exclusivo está redondamente enganada, mas o purismo do PITR também costuma criar armadilhas operacionais graves quando aplicado sem critério em servidores próprios.
O pg_dump é uma ferramenta de exportação lógica, não uma estratégia de continuidade de negócio para bases vivas. Quando você roda um dump em uma base de dados ativa com dezenas de tabelas recebendo escrita, o PostgreSQL mantém uma transação longa com nível de isolamento serializável ou snapshot. Isso gera três problemas imediatos.
Primeiro, transações longas impedem que o processo de autovacuum limpe registros mortos nas tabelas mais quentes, inflando o tamanho das páginas em disco e degradando a memória temporária.
Segundo, o RPO (Recovery Point Objective) de um dump diário é inaceitável para quase qualquer negócio sério. Se o seu banco corromper às 18h e o último dump ocorreu às 3h da manhã, você perdeu quinze horas de transações de clientes. Tentar reconciliar isso via logs de aplicação ou eventos perdidos é um pesadelo manual que custa dias de trabalho e credibilidade.
Terceiro, e mais grave: restaurar um dump lógico de centenas de gigabytes é dolorosamente lento. O pg_restore precisa recriar cada índice, validar restrições de chave estrangeira e rodar verificações linha por linha. O que levou quarenta minutos para ser extraído pode levar seis, oito ou doze horas para ser reconstruído em um servidor novo sob estresse. Enquanto isso, o sistema permanece inacessível.
Além disso, o pg_dump padrão não exporta usuários, senhas, papéis globais nem configurações de cluster. Sem o pg_dumpall --globals-only, você restaura as tabelas, mas sua aplicação Rails não consegue sequer autenticar no banco novo porque o usuário da conexão simplesmente não existe.
Reconhecendo as limitações do dump, muitos engenheiros correm para o extremo oposto e tentam configurar Point-in-Time Recovery (PITR) na unha em servidores virtuais privados. É aqui que o consenso da documentação oficial quebra contra a realidade da infraestrutura enxuta.
Para que o PITR funcione, o PostgreSQL precisa arquivar cada segmento de 16 MB de WAL assim que ele é fechado. O mecanismo padrão é o parâmetro archive_command no postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /mnt/wal_archive/%f && cp %p /mnt/wal_archive/%f'
O perigo invisível dessa abordagem reside no comportamento do motor quando o comando de cópia falha. Se o destino do arquivo encher, se a conexão de rede oscilar ou se o script travar por falta de timeout, o PostgreSQL não descarta os arquivos de log. Ele os mantém na pasta local pg_wal.
Em poucos minutos de escrita pesada, a partição do banco enche cem por cento. Quando o disco zera o espaço disponível, o PostgreSQL executa um shutdown de emergência para evitar corrupção. O sistema que deveria proteger contra desastres acaba derrubando o ambiente produtivo em uma noite de tráfego intenso.
Eu já enfrentei servidores paralisados porque o script de sincronização de WAL para um bucket S3 compatível acumulou processos zumbis por falta de tratamento de sinais no shell. Ferramentas como o pgBackRest resolvem boa parte dessa complexidade ao gerenciar retries, compressão paralela e remoção de WALs antigos, mas elas exigem um servidor dedicado de backup ou configuração cuidadosa de credenciais e permissões no host.
Em nossa infraestrutura, adotamos um caminho que equilibra a velocidade de recuperação com a simplicidade operacional. Em vez de depender exclusivamente de um arquivo lógico ou montar um cluster complexo de ferramentas corporativas, separamos o processo em duas camadas mecânicas.
A primeira camada é a cópia física do cluster usando pg_basebackup. Esse utilitário copia os blocos binários do diretório de dados enquanto o banco continua rodando, sem bloquear escritas normais e sem forçar reconstrução de índices na hora da restauração:
pg_basebackup -h 127.0.0.1 -U replicador -D /backups/base_$(date +%Y%m%d) -Ft -z -P
A segunda camada é a recepção contínua dos registros de transação via streaming, utilizando o utilitário pg_receivewal rodando como serviço em uma máquina separada na mesma rede privada. Ele se conecta via protocolo de replicação e grava os WALs em tempo real, eliminando a dependência do comando de arquivo síncrono no servidor principal.
Se o banco produtivo sofrer uma pane catastrófica, o procedimento de recuperação exige apenas descompactar o último pg_basebackup, apontar o diretório de arquivos WAL recuperados e iniciar o serviço definindo o momento exato de parada com o arquivo de controle recovery.signal:
restore_command = 'cp /storage/wal/%f %p'
recovery_target_time = '2026-09-19 14:22:00-03'
recovery_target_action = 'promote'
A restauração de uma base física leva apenas o tempo de descompactação e leitura sequencial de disco, permitindo voltar o sistema em minutos, não em horas.
Nada do que descrevi acima tem valor se o processo não for executado do início ao fim longe do ambiente de produção. Um backup não testado tem exatamente o mesmo valor de um backup inexistente. Arquivos corrompem na transferência, permissões mudam em atualizações de sistema operacional e diretórios ficam órfãos sem aviso.
Em vez de confiar em notificações de sucesso no terminal, mantemos uma rotina automatizada semanal que provisiona uma VPS temporária descartável, baixa a base física mais recente, aplica os WALs acumulados, inicia o processo do PostgreSQL e executa uma bateria de verificações de sanidade:
## Sobe o banco restaurado na máquina de testes
pg_ctl -D /var/lib/postgresql/data_teste start
## Executa consulta de integridade básica via socket local
psql -d app_production -c "SELECT count(*) FROM users;"
psql -d app_production -c "SELECT amcheck_test_indexes();"
Usamos a extensão amcheck nativa do PostgreSQL para verificar a integridade estrutural das páginas dos índices B-tree. Se o script encontrar corrupção silenciosa ou discrepância de leitura, o alarme soa muito antes de precisarmos desse arquivo em uma emergência.
Admito que essa rotina de validação automatizada consome largura de banda e exige uma máquina temporária para rodar o teste, o que adiciona alguns dólares à fatura mensal de hospedagem. Também reconheço que, para bases que ultrapassam vários terabytes, a transferência contínua de blocos exige planejamento rigoroso de taxa de transferência de disco e conexões de rede interna.
Mesmo com esses custos operacionais, o preço de validar um desastre simulado toda semana é infinitamente menor do que o desespero de descobrir, às quatro da manhã de um domingo, que seu arquivo compactado de backup contém apenas mensagens de erro de permissão negada.
CTO e arquiteto full stack especializado em Ruby on Rails, Vue.js, sistemas multi-tenant e infraestrutura distribuída.