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 · Publicado em · 9 min de leitura

baldes e bancos baixos alinhados perto de janelas, iluminados por luz natural
Imagem limpa e sem textos, sugere armazenamento e espaço limitado Foto: Jimmy Liao / Pexels

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ário

Veja também