Replicação e Backup
Aula 5 de 7
WAL — Write Ahead Log
-- WAL: todo dado é escrito no log antes de ir para o data file
-- Garante atomicidade e durabilidade (A e D do ACID)
-- Configurações WAL
SHOW wal_level; -- replica, logical, minimal
SHOW wal_buffers; -- 16MB default
SHOW wal_keep_size; -- 1GB (retention)
SHOW max_wal_size; -- 1GB (checkpoint trigger)
SHOW min_wal_size; -- 80MB
-- Ver LSN atual
SELECT pg_current_wal_lsn();
SELECT pg_last_wal_receive_lsn();
SELECT pg_last_wal_replay_lsn();
-- Ver arquivos WAL
SELECT * FROM pg_ls_waldir();
Streaming Replication
Primary (standby.signal ausente)
# postgresql.conf (PRIMARY)
wal_level = replica
max_wal_senders = 10 # número máximo de standbys
wal_keep_size = 1024 # MB para manter WAL
max_replication_slots = 10
synchronous_commit = on # aguarda standby confirmar
synchronous_standby_names = 'FIRST 1 (standby1)'
# pg_hba.conf (PRIMARY)
# Permitir replicação do IP do standby
host replication replicator 192.168.1.20/32 scram-sha-256
Standby (hot standby)
# postgresql.conf (STANDBY)
primary_conninfo = 'host=192.168.1.10 port=5432 user=replicator password=senha'
hot_standby = on
hot_standby_feedback = on # evita clean conflicts
# Criar arquivo de sinalização
touch /var/lib/postgresql/16/main/standby.signal
# Fazer base backup
pg_basebackup -h 192.168.1.10 -D /var/lib/postgresql/16/main \
-U replicator -v -P --wal-method=stream
# Iniciar standby (inicia como réplica automaticamente)
sudo systemctl start postgresql
Verificação
-- No primary: verificar replicação
SELECT pid, application_name, state, sync_state, write_lag
FROM pg_stat_replication;
-- No standby: verificar status
SELECT pg_is_in_recovery(); -- true se standby
SELECT pg_last_wal_receive_lsn();
SELECT pg_last_wal_replay_lsn();
SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS lag;
Logical Replication
-- Publicação (PUBLISHER)
CREATE PUBLICATION pub_vendas
FOR TABLE clientes, pedidos, itens_pedido
WITH (publish = 'insert, update, delete');
CREATE PUBLICATION pub_todos
FOR ALL TABLES;
-- Assinatura (SUBSCRIBER)
CREATE SUBSCRIPTION sub_vendas
CONNECTION 'host=192.168.1.10 port=5432 dbname=db user=replicator password=senha'
PUBLICATION pub_vendas;
-- Gerenciar
ALTER PUBLICATION pub_vendas ADD TABLE produtos;
ALTER PUBLICATION pub_vendas DROP TABLE itens_pedido;
DROP SUBSCRIPTION sub_vendas;
-- Monitorar
SELECT * FROM pg_stat_subscription;
SELECT * FROM pg_replication_slots;
pg_dump / pg_dumpall / pg_restore
pg_dump (por database)
# Formato custom (recomendado: compressão + paralelo)
pg_dump -h localhost -U postgres -Fc meubanco > meubanco.dump
# Formato plain (SQL texto)
pg_dump -U postgres meubanco > meubanco.sql
# Apenas schema (sem dados)
pg_dump -U postgres --schema-only meubanco > schema.sql
# Apenas dados (sem schema)
pg_dump -U postgres --data-only --exclude-table=logs meubanco > dados.sql
# Comprimir e paralelo
pg_dump -U postgres -Fd -j 4 meubanco -f /backup/dir/ # directory format + jobs
# Tabelas específicas
pg_dump -U postgres -t clientes -t pedidos meubanco > vendas.sql
pg_dumpall (tudo)
# Backup completo do cluster (roles, tablespaces, databases)
pg_dumpall -U postgres > cluster.sql
# Apenas roles e tablespaces
pg_dumpall -U postgres --globals-only > globals.sql
pg_restore
# Restaurar custom dump
pg_restore -U postgres -d meubanco meubanco.dump
# Com paralelismo
pg_restore -U postgres -d meubanco -j 4 meubanco.dump
# Apenas schema
pg_restore -U postgres --schema-only -d meubanco meubanco.dump
# Listar conteúdo do dump
pg_restore -l meubanco.dump
# Restaurar tabelas específicas
pg_restore -U postgres -d meubanco -t clientes -t pedidos meubanco.dump
# Sobrescrever objetos existentes (--clean)
pg_restore -U postgres --clean --if-exists -d meubanco meubanco.dump
PITR — Point In Time Recovery
# postgresql.conf (para WAL archiving)
wal_level = replica
archive_mode = on
archive_command = 'cp %p /backup/wal/%f'
archive_timeout = 60 # forçar arquivamento a cada 60s
# 1. Fazer base backup
pg_basebackup -h localhost -U postgres -D /backup/base \
-Fp -Xs -P -v
# -Fp: plain format (diretório)
# -Xs: incluir WAL no backup
# 2. Simular desastre
sudo systemctl stop postgresql
rm -rf /var/lib/postgresql/16/main/
# 3. Restaurar base backup
cp -r /backup/base/* /var/lib/postgresql/16/main/
# 4. Criar recovery.conf (PostgreSQL < 12) ou recovery.signal
cat > /var/lib/postgresql/16/main/recovery.signal
# 5. Configurar recovery (no postgresql.conf ou recovery.conf)
restore_command = 'cp /backup/wal/%f %p'
recovery_target_time = '2024-06-15 14:30:00 UTC'
# recovery_target_lsn = '0/1A2B3C4D'
# recovery_target_xid = '123456'
# recovery_target = 'immediate' # para mais recente possível
# 6. Iniciar PostgreSQL (aplica WAL até o target)
sudo systemctl start postgresql
# 7. Verificar recovery
SELECT pg_is_in_recovery();
SELECT pg_last_wal_replay_lsn();
SELECT recovery_status FROM pg_stat_progress_recovery;
pgBackRest
# Instalação
sudo apt install pgbackrest -y
# Configuração /etc/pgbackrest/pgbackrest.conf
cat << EOF | sudo tee -a /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/backup/pgbackrest
repo1-retention-full=2
repo1-cipher-type=aes-256-cbc
compress-type=gz
process-max=3
[mycluster]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432
EOF
# Backup
sudo -u postgres pgbackrest --stanza=mycluster --type=full backup
sudo -u postgres pgbackrest --stanza=mycluster --type=diff backup
sudo -u postgres pgbackrest --stanza=mycluster --type=incr backup
# Listar backups
sudo -u postgres pgbackrest --stanza=mycluster info
# Restaurar
sudo -u postgres pgbackrest --stanza=mycluster --type=time \
--target="2024-06-15 14:30:00" restore
Lab: Script de Backup e Réplica
cat > pg-manager.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail
readonly PGUSER="postgres"
readonly PGHOST="localhost"
readonly BACKUP_DIR="/backup"
readonly DATE=$(date +%Y%m%d-%H%M%S)
backup_full() {
local db="$1"
echo "=== BACKUP FULL: $db ==="
pg_dump -U "$PGUSER" -h "$PGHOST" -Fc -Z 9 \
-f "$BACKUP_DIR/$db-$DATE.dump" "$db"
echo "Backup: $BACKUP_DIR/$db-$DATE.dump"
ls -lh "$BACKUP_DIR/$db-$DATE.dump"
}
backup_all() {
echo "=== BACKUP ALL DATABASES ==="
pg_dumpall -U "$PGUSER" -h "$PGHOST" \
-f "$BACKUP_DIR/cluster-$DATE.sql"
gzip "$BACKUP_DIR/cluster-$DATE.sql"
echo "Backup: $BACKUP_DIR/cluster-$DATE.sql.gz"
}
backup_wal() {
echo "=== BACKUP WAL ==="
psql -U "$PGUSER" -h "$PGHOST" -c "SELECT pg_switch_wal();" 2>/dev/null || true
psql -U "$PGUSER" -h "$PGHOST" -c "SELECT pg_backup_start('manual_backup');"
rsync -az /var/lib/postgresql/16/main/pg_wal/ "$BACKUP_DIR/wal-$DATE/"
psql -U "$PGUSER" -h "$PGHOST" -c "SELECT pg_backup_stop();"
}
restore() {
local dump="$1"
local db="$2"
echo "=== RESTORE: $dump -> $db ==="
pg_restore -U "$PGUSER" -h "$PGHOST" -d "$db" -j 4 --clean "$dump"
}
case "${1:-}" in
backup) backup_full "${2:-meubanco}" ;;
backup-all) backup_all ;;
wal) backup_wal ;;
restore) restore "$2" "${3:-meubanco}" ;;
*)
echo "Uso: $0 {backup [db] | backup-all | wal | restore <dump> [db]}"
exit 1
;;
esac
SCRIPT
chmod +x pg-manager.sh
WAL é a base da durabilidade e replicação. Streaming replication mantém hot standby síncrono ou assíncrono. Logical replication permite replicação seletiva entre versões. pg_dump -Fc com compressão e paralelo é o padrão ouro. PITR recupera até um ponto específico no tempo.