Guia de backup e recuperação PostgreSQL com wal‑shipping e basebackup em VPS com espaço limitado: prática de baixo uso de disco
Por Kevin Marcondes · Publicado em · 9 min de leitura
Guia de backup e recuperação PostgreSQL com wal‑shipping e basebackup em VPS com espaço limitado. Você verá configurações objetivas, scripts e decisões práticas para economizar disco local. O foco é manter basebackups enxutos, enviar WAL comprimido para armazenamento externo e garantir recuperação ponto‑no‑tempo (PITR) testável, sem promessas irreais.
Cenário: VPS com pouco disco e o que realmente importa
Em VPS pequenas, o gargalo costuma ser o disco. Backups completos locais estouram o volume e dificultam a restauração.
A solução é reduzir o footprint local. Envie o histórico de WAL para fora e mantenha basebackups compactos.
Objetivo: um basebackup recente e fluxo contínuo de WAL arquivado. Ambos fora do disco principal.
Sinais de necessidade: falhas por falta de espaço, pg_wal crescendo e restaurações lentas por cópias grandes.
Nos tópicos seguintes, tratamos escolhas práticas: compressão, destino, retenção e automação com segurança.
- Evitar retenção longa no disco local
- Enviar WAL comprimido para armazenamento externo
- Executar basebackup com WAL separado (-X none)
- Testar restauração e PITR com regularidade
Arquitetura recomendada: basebackup + WAL shipping comprimido
Use dois fluxos: 1) basebackup periódico e 2) WAL shipping contínuo e comprimido. Ambos seguem para armazenamento externo.
No disco local, mantenha apenas o essencial. O histórico de WAL não precisa ficar retido localmente além do mínimo.
Políticas de ciclo de vida no bucket controlam custos e retenção com segurança.
Se já usa S3‑compatível, integre com snapshots e uploads incrementais em LVM snapshots + Restic em S3. Em cenários que exigem PITR granular, complemente com este fluxo de WAL.
Este desenho atende ao objetivo do guia de backup e recuperação PostgreSQL com wal‑shipping e basebackup em VPS com espaço limitado.
- Basebackup periódico: ponto inicial da restauração
- WAL shipping contínuo: cobre o intervalo entre basebackups
- Retenção definida por políticas no bucket
- Alertas automáticos em caso de falha de arquivamento
Configurar PostgreSQL para archiving eficiente (sem lotar o disco)
Ative o archiving e defina um comando que comprima e transfira os WALs para fora. Em versões 13+, prefira wal_keep_size baixo.
Em versões antigas, ajuste wal_keep_segments. Evite retenções locais agressivas se a meta é poupar disco.
Use um wrapper script no archive_command. Ele cuida de compressão, upload e logs, e simplifica a manutenção.
# postgresql.conf (excertos)
wal_level = replica
archive_mode = on
archive_command = '/usr/local/bin/pg-archive-wal %p %f'
max_wal_size = 1GB # ajuste conforme sua carga
# Em PG >= 13
wal_keep_size = 64MB # manter o mínimo necessário
# Em PG <= 12 use wal_keep_segments apropriadamente baixo
# Opcional, se disponível na sua versão:
# wal_compression = on # reduz tamanho do WAL gerado
Wrapper de archive_command: compressão + upload (S3 ou SSH)
O archive_command precisa ser idempotente e rápido. Se falhar, o PostgreSQL tenta novamente.
Nunca remova arquivos locais antes de confirmar o upload. Abaixo, um wrapper com zstd e dois destinos: S3‑compatível e servidor remoto via SSH.
Adapte variáveis e paths. Registre logs. Monitore sempre o código de retorno.
#!/usr/bin/env bash
# /usr/local/bin/pg-archive-wal
# Uso: pg-archive-wal <path_absoluto_wal> <nome_arquivo_wal>
set -euo pipefail
PATH=/usr/local/bin:/usr/bin:/bin
SRC_PATH="$1"
WAL_NAME="$2"
LOG=/var/log/postgresql/wal-archive.log
COMP_LEVEL=${COMP_LEVEL:-3} # trade-off CPU x compactação
DEST_MODE=${DEST_MODE:-s3} # s3|ssh
case "$DEST_MODE" in
s3)
: "${S3_BUCKET:?Defina S3_BUCKET}"
# Envia fluxo comprimido (stdin) para bucket S3-compatível
zstd -T0 -${COMP_LEVEL} -c -- "$SRC_PATH" \
| aws s3 cp - "s3://${S3_BUCKET}/wal/${WAL_NAME}.zst" --only-show-errors \
&& echo "$(date -Is) OK S3 ${WAL_NAME}" >> "$LOG"
;;
ssh)
: "${SSH_HOST:?Defina SSH_HOST}" "${SSH_PATH:?Defina SSH_PATH}"
zstd -T0 -${COMP_LEVEL} -c -- "$SRC_PATH" \
| ssh -o StrictHostKeyChecking=yes "$SSH_HOST" \
"cat > '${SSH_PATH}/wal/${WAL_NAME}.zst'" \
&& echo "$(date -Is) OK SSH ${WAL_NAME}" >> "$LOG"
;;
*)
echo "Modo de destino inválido: $DEST_MODE" >&2; exit 2;;
esac
# Importante: NÃO remover o arquivo de origem; o PostgreSQL gerencia.
Basebackup enxuto (-X none) e envio direto ao armazenamento externo
Execute um CHECKPOINT antes do basebackup e evite incluir WAL no pacote (-X none). Você não duplica dados.
Comprima em stream e envie ao destino externo. Teste sua versão: alguns flags mudam entre releases.
Se preferir gerar localmente, compacte após finalizar e envie. Isso reduz a janela de inconsistência.
# 1) Checkpoint para estabilizar o backup
psql -U postgres -d postgres -c "CHECKPOINT;"
# 2) Basebackup local, formato tar, sem WAL incluso; compacta depois
pg_basebackup -U postgres -Ft -X none -D /backups/base/$(date +%F) -v --progress
find /backups/base -type f -name "*.tar" -print0 | xargs -0 -I{} zstd -T0 -3 {}
aws s3 cp /backups/base/ s3://$S3_BUCKET/base/ --recursive --exclude "*" --include "*.zst"
# 3) Alternativa: enviar em stream direto para o bucket
pg_basebackup -U postgres -Ft -X none -D - -v --progress \
| zstd -T0 -3 \
| aws s3 cp - s3://$S3_BUCKET/base/$(date +%F).tar.zst --only-show-errors
# 4) Opcional: limitar taxa de leitura para proteger o I/O do servidor.
Como restaurar e fazer PITR usando WAL arquivado (passo a passo)
O processo: recuperar o basebackup, preparar o diretório de dados e configurar restore_command para buscar os WALs arquivados.
Para recuperar a um instante (PITR), defina um recovery_target. Atenção: os passos removem dados do diretório atual. Teste antes.
Para um caso prático de perda acidental de tabela, veja recuperar via PITR sem downtime.
# 1) Parar o PostgreSQL e preparar diretório
sudo systemctl stop postgresql
sudo rm -rf "$PGDATA"/* # ATENÇÃO: isso apaga dados atuais
# 2) Restaurar o basebackup
aws s3 cp s3://$S3_BUCKET/base/2023-12-01.tar.zst - \
| zstd -d \
| tar -x -C "$PGDATA"
# 3) Configurar restore_command e (opcional) PITR
cat >> "$PGDATA/postgresql.auto.conf" <<'EOF'
restore_command = 'aws s3 cp s3://BUCKET/wal/%f.zst - | zstd -d -c > %p'
recovery_target_time = '2023-12-01 14:32:00+00' # comente para recuperar até o fim do WAL
EOF
# 4) Criar recovery.signal (PG >= 12)
touch "$PGDATA/recovery.signal"
chown -R postgres:postgres "$PGDATA"
chmod 700 "$PGDATA"
# 5) Subir e acompanhar logs
sudo systemctl start postgresql
# Acompanhe logs até o término do replay e remoção de recovery.signal
Retenção, compressão e custos: escolhas e trade‑offs práticos
Com disco limitado, priorize compressão no archive_command e retenção curta no bucket. A compressão consome CPU; use níveis moderados, como zstd -3.
Defina políticas no bucket para expirar WALs antigos após um novo basebackup válido. Classes de armazenamento mais baratas reduzem custos, porém aumentam a latência de restauração.
Para um pipeline incremental e criptografado de arquivos diversos, avalie backups incrementais criptografados.
- Rotina sugerida: basebackup semanal + WAL contínuo
- WAL: cobrir o intervalo entre basebackups, nada além
- Política: expirar WALs após novo basebackup confirmado
- Compressão: níveis moderados para não disputar CPU
| Opção | Impacto em disco | Impacto em CPU | Risco | Quando usar |
|---|---|---|---|---|
| Sem compressão | Maior uso | Baixo | Custo e restauração mais lenta | CPU muito limitada |
| gzip nível médio | Médio | Médio | Upload mais lento se CPU saturar | Ambiente balanceado |
| zstd nível 3 | Baixo | Baixo/Médio | CPU adicional em picos | Boa taxa/velocidade |
| Armazenamento classe fria | Custo menor | N/A | Maior latência para recuperar | Backups raramente acessados |
Monitorar o archiving, validar restaurações e checklist final
Sem monitoramento, o archiving pode falhar por dias. Observe pg_stat_archiver, o tamanho de pg_wal e datas no bucket.
Programe restaurações de teste em ambiente isolado e validações de integridade. Combine com um checklist de hardening em segurança para VPS Linux.
Use esta lista para fechar a configuração com foco em espaço e recuperação confiável.
- archive_mode=on e archive_command testado sob falha de rede
- Compressão habilitada com nível moderado e validado em pico
- Basebackup periódico com -X none e teste de recuperação real
- Políticas de expiração no bucket coerentes com sua janela de PITR
- Alertas para atrasos no archiving e crescimento do pg_wal
- Procedimento de restauração documentado, versionado e revisado
-- Verificar atividade do archiver
SELECT now() AT TIME ZONE 'utc' AS now_utc,
last_archived_wal,
last_archived_time AT TIME ZONE 'utc' AS last_archived_utc,
failed_archives, stats_reset
FROM pg_stat_archiver;
-- Estimar volume de WAL local (via shell)
-- du -sh $PGDATA/pg_wal
-- Listar objetos no bucket por data
Quando esta abordagem não é suficiente e alternativas possíveis
Se a taxa de escrita é muito alta, o custo de upload e retenção pode crescer rápido. Reduza o intervalo de basebackup ou use compressão mais agressiva fora do pico.
Se o bucket não é opção, use um servidor de backup dedicado via SSH. Combine com verificação periódica e rotação automatizada.
Integre com snapshots e uploads incrementais quando fizer sentido, como no guia de LVM snapshots + Restic em S3.
Perguntas frequentes
Qual a frequência ideal do basebackup em uma VPS com pouco disco?
Depende do volume de escrita e do histórico desejado. Em muitos cenários, semanal com WAL shipping contínuo equilibra espaço e tempo de recuperação. Ajuste conforme custo do bucket e metas de RPO/RTO.
WAL shipping consome muita CPU por causa da compressão?
Com compressão moderada, como zstd nível 3, o impacto costuma ser aceitável. Em picos, reduza o nível ou serialize uploads. Monitore saturação de CPU e ajuste ao perfil da aplicação.
É seguro usar -X none no pg_basebackup?
Sim, desde que o archiving funcione e você retenha WAL suficiente para cobrir do momento do basebackup até o alvo de recuperação. Sem WAL arquivado, a restauração fica limitada ao estado do basebackup.
Como lidar com falhas no envio para o bucket?
O archive_command retorna erro e o PostgreSQL reintenta. Registre logs, monitore pg_stat_archiver e configure alertas. Em falhas prolongadas, o pg_wal cresce. Garanta folga de disco e um procedimento de retomada.
Posso criptografar os arquivos antes de enviar?
Sim. Você pode encapsular o fluxo com criptografia antes do upload ou usar criptografia no bucket. Avalie impacto de CPU e gestão de chaves. Em S3‑compatível, habilite políticas de criptografia padrão.
Quer validar sua estratégia de backup e recuperação?
Se você opera PostgreSQL em VPS com pouco disco e precisa de PITR confiável, uma revisão dos scripts e testes de restauração é o próximo passo natural.
Conversar sobre seu cenárioVeja também
- Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados
- Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção
- Guia prático para dimensionamento de VPS e tuning de PHP‑FPM para lojas Magento/OpenMage com picos sazonais: do sizing ao teste de carga
- guia prático: reconstruir índices no PostgreSQL em produção usando CREATE INDEX CONCURRENTLY e índices parciais (passo a passo seguro)