Para quem é
Você mantém um único servidor PostgreSQL, em uma VPS ou em uma máquina esquecida no armário, e o seu backup é um pg_dump noturno. Isso protege você contra a perda do disco. Não ajuda quando alguém roda DELETE FROM orders sem WHERE às 10:15 e você só percebe às 10:40. O dump da noite anterior devolve você 12 horas no tempo. A recuperação point-in-time devolve você às 10:14.
pgBackRest e Barman são ferramentas completas, e aprender qualquer uma leva uma tarde. Para um servidor pequeno e único, este kit é a versão curta: scripts bash, um arquivo, um cluster, nada escondido.
O que ele faz
- Arquivamento contínuo de WAL, configurado do jeito seguro: nunca sobrescreve um arquivo, falha alto quando o disco está cheio ou somente leitura, e detecta um arquivamento com defeito antes de o disco encher.
- Base backups verificados com
pg_verifybackupdepois de prontos, compactados e conferidos contra um checksum. - Retenção que calcula o que apagar a partir do base backup mais antigo que você mantém, então não corre o risco de remover um WAL de que um backup mantido ainda precisa.
- Restauração para um timestamp, um LSN, um restore point nomeado ou o WAL arquivado mais recente, em um diretório novo, com o tratamento de timeline já resolvido.
- Um monitor no cron que confere a idade do último segmento arquivado e o backlog, com alertas por Telegram ou webhook que não se repetem e avisam quando tudo volta ao normal.
- Um drill que gera dados, faz um backup, comete um erro de propósito, destrói o servidor e o restaura em um container limpo, depois compara contagens de linhas e checksums.
O uso no dia a dia
É assim que ficam os comandos do dia a dia e os de emergência. Os scripts são bash puro, e você pode ler todos eles.
./backup-base.sh && ./prune.sh # nightly
./check-archive.sh # every 5 minutes, exit code plus alert
./verify-archive.sh # daily: is the WAL chain complete?
# the bad DELETE happened around 10:15 UTC
./restore-to-time.sh --target-dir /srv/restore/r1 \
--time "2026-11-09 10:14:59+00" --start --port 5433
psql -h /tmp -p 5433 -d postgres # look around, then copy back what you need
Outros alvos: --name before_migration (um restore point que você criou), --lsn 0/5000060 e restore-latest.sh para uma recuperação de desastre simples. A opção --pause interrompe a recuperação no alvo, para você inspecionar os dados em modo somente leitura antes de decidir.
O que ele se recusa a fazer
A maior parte do trabalho foi nas coisas que não podem dar errado em silêncio.
- Um segmento de WAL faltando no meio do arquivo. A restauração para, diz qual é o segmento e sai com código diferente de zero. Nos nossos testes, forçar a restauração devolveu 200 de 410 linhas sem nenhum erro, e é exatamente por isso que ela recusa por padrão.
- Um horário alvo anterior ao primeiro base backup, restaurar sobre um diretório de dados que não está vazio ou sobre o que está em uso, e rodar como root.
- Sobrescrever um arquivo já arquivado, inclusive quando um servidor restaurado reinicia a numeração das timelines.
- Apagar um WAL de que um base backup mantido precisa.
- Tablespaces. O script de backup para em vez de produzir algo que não vai restaurar.
Medições
Uma execução em uma máquina ARM64 de porte de notebook, com PostgreSQL nas configurações padrão.
Tempo de restauração (destrói o servidor, restaura em um container limpo)
| Pequeno | Grande | |
|---|---|---|
| Dados | 200,000 linhas na tabela principal, 78 MB | 5,000,000 linhas, 989 MB |
| Restauração, total | 2.4 s | 42.0 s |
| dos quais início e replay do WAL | 2.0 s | 36.1 s |
| Contagem de linhas e checksums | batem | batem |
Quanto você pode perder
20 inserts por segundo, depois kill -9 e uma restauração só a partir do arquivo. "Perdido" quer dizer commits que foram confirmados, mas não existiam depois.
archive_timeout | Confirmados | Recuperados | Perdidos |
|---|---|---|---|
| 10 s | 794 | 764 | 30 (o commit perdido mais recente era 1.9 s mais novo que o estado recuperado) |
| 10 s | 513 | 400 | 113 (6.1 s) |
| 60 s | 1,896 | 1,175 | 721 (36.0 s) |
| 0 (padrão do PostgreSQL) | 740 | 0 | tudo desde o base backup |
A última linha é a que vale guardar. Com o archive_timeout padrão e um servidor parado, perder o disco significa perder tudo o que veio depois do último base backup. O guia explica essa configuração e o custo dela: um switch forçado arquiva um arquivo inteiro de 16 MiB, a menos que você comprima.
Overhead
pgbench, cinco rodadas intercaladas: mediana de 5,156 tps com o arquivamento desligado, 5,112 com gzip e 5,167 sem compressão. As diferenças ficam dentro da variação de 2 por cento entre as rodadas: nesta máquina, o arquivamento não apareceu como overhead.
Como foi testado
122 checks automatizados no PostgreSQL 15 (pacote do Debian) e de novo no PostgreSQL 17 (PGDG), em containers Debian 12 limpos, mais o drill de destruir e restaurar com dois containers em cada versão. Eles cobrem um arquivamento com falha que impede a reciclagem do WAL, o comando de arquivamento em destino local e SFTP, base backups com um arquivo corrompido, todos os alvos de restauração, uma segunda recuperação em uma nova timeline, a retenção e todas as recusas acima.
Requisitos
Debian 12 com o empacotamento do PostgreSQL do Debian, um cluster, bash, curl para os alertas e openssh-client se você arquivar por SFTP. Você precisa de root para a instalação e do usuário postgres para todo o resto.
Perguntas frequentes
Já uso o pgBackRest. Preciso disto?
Não necessariamente. O pgBackRest é uma ferramenta completa. Este kit é para quando você quer algo pequeno o bastante para ler inteiro, ou uma forma de entender o que o pgBackRest faz por você.
Dá para restaurar uma tabela só?
Você restaura o cluster inteiro em um diretório novo, no ponto que escolher, e depois copia de lá a tabela de que precisa. O drill usa exatamente esse padrão.
Funciona com Docker ou com Postgres gerenciado?
Não. Ele precisa de acesso à configuração e aos arquivos do servidor. Em um serviço gerenciado, use a recuperação point-in-time do próprio provedor.
Quanto de disco ele consome?
Depende do volume de escrita e do archive_timeout. O guia traz volumes de WAL para algumas cargas e os números de compressão que medimos.
Licença
Uso nos seus próprios servidores e nos da sua empresa. Não revenda nem redistribua os arquivos.
Changelog
- 0.1.0: primeira release.
Ler mais
- Restore PostgreSQL to a timestamp with recovery_target_time (em inglês)
- PostgreSQL WAL archiving from scratch on a single Debian VPS (em inglês)
- How much data a disk failure costs with WAL archiving (em inglês)
- pg_dump vs physical backup vs PITR: which to use (em inglês)
Quero este
Pagamento, impostos e notas fiscais ficam com a Polar, que atua como merchant of record. Você recebe o link de download assim que concluir a compra.