pg_dump ile uğraşmayı bıraktığım gün, sistem yazılım mühendisi olarak ciddiyetimin arttığını düşünüyorum. pg_dump bir araştırma aracı — production yedek aracı değil.

Üretim yedeği üç şeyi sağlamalı:

  1. Point-in-time recovery (PITR). “Dün gece 02:13’te silindi” diyebilmek.
  2. Bütünlük doğrulaması. Yedek dosyasının açıldığında çalıştığını test etmek.
  3. Saklamayı politikayla yönetmek. 6 saatlik/günlük/haftalık rotasyon.

pg_dump üç maddeyi de karşılamıyor.

pgBackRest kurulumu

Ben hem yerel hem de S3 yedeği almayı tercih ve tavsiye ediyorum. Yerel yedekler hızlı, S3 yedekleri ise yangına dayanıklı.

Off-site kopya

Repository tek bir diskte duruyorsa bir VPS yangını her şeyi siler. pgBackRest S3 veya S3-uyumlu (R2, MinIO) bucket’a yazabiliyor:

Tercih: bucket’ı versiyon-kilitli ve delete’i yasaklayan bir policy ile koruyun. Ransomware senaryosunda kritik.

Maliyetleri uzun vadeli kontrol altında tutmak için bucket yaşam döngüsünü ayarlayın:

30 Gün → Glacier Anında Alma → 120 Gün → Sil

/etc/pgbackrest.conf:

[global]

###################################
# Local Repository
###################################
repo1-path=/var/lib/pgbackrest
repo1-retention-full=4
repo1-retention-diff=14
repo1-bundle=y
repo1-block=y
repo1-cipher-pass=...
repo1-cipher-type=aes-256-cbc

###################################
# AWS S3 Repository
###################################
repo2-type=s3
repo2-path=/main
repo2-s3-bucket=...
repo2-s3-endpoint=s3.{region_name}.amazonaws.com
repo2-s3-region={region_name}
repo2-s3-key=...
repo2-s3-key-secret=...
repo2-bundle=y
repo2-block=y
repo2-cipher-type=aes-256-cbc
repo2-cipher-pass=...

###################################
compress-type=zst
compress-level=6
process-max=4
start-fast=y
log-level-console=info
log-level-file=detail
log-path=/var/log/pgbackrest

[main]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

Yetkileri sıkılaştırın:

sudo chown postgres:postgres /etc/pgbackrest.conf
sudo chmod 640 /etc/pgbackrest.conf

Stanza oluşturun:

sudo -u postgres pgbackrest --stanza=main stanza-create

postgresql.conf tarafında ise WAL archiving’i pgBackRest’e yönlendiriyoruz:

archive_mode = on
archive_command = 'pgbackrest --stanza=main archive-push %p'
archive_timeout = 60
wal_level = replica

archive_timeout = 60 — son 60 saniyenin işlemleri kaybedilebilir; çoğu uygulama için yeterli, finansal işlemler için değil.

Backup planı

Cron tarafında:

# Yerel repository (repo1)
0 2 * * 0          pgbackrest --stanza=main --repo=1 --type=full backup
0 2 * * 1-6        pgbackrest --stanza=main --repo=1 --type=diff backup
0 0,6,12,18 * * *  pgbackrest --stanza=main --repo=1 --type=incr backup

# S3 repository (repo2)
0 4 * * 0          pgbackrest --stanza=main --repo=2 --type=full backup
0 4 * * 1-6        pgbackrest --stanza=main --repo=2 --type=diff backup
0 3,9,15,21 * * *  pgbackrest --stanza=main --repo=2 --type=incr backup

İki repo yapılandırıldığında --repo şart: verilmezse pgBackRest yalnızca en yüksek öncelikli repoya (repo1) yedek alır, S3’te arşivlenen WAL’dan başka bir şey durmaz — tek başına restore edilemeyen bir kopya.

Her repoda haftalık full, günlük diff, 6 saatlik incremental. Storage tüketimi şaşırtıcı derecede düşük — konfigürasyondaki repoN-bundle/repoN-block satırları block incremental yedeği açıyor, böylece pgBackRest dosyanın tamamını değil yalnızca değişen bloklarını kopyalıyor; ikisi de varsayılanda kapalı.

Bütünlük: yedek varsa restore edilebilir mi?

Yedeği almak yeterli değil. Haftada bir restore tatbikatı:

pgbackrest --stanza=main --delta restore --pg1-path=/tmp/pg_restore_test

Sonra o instance’ı geçici bir port üzerinde başlatıp birkaç sanity query çalıştırıyorum. Bu adım atlanırsa yedek sahte güven olur.

PITR provası

Belirli bir zamana geri dönmek:

pgbackrest --stanza=main \
  --type=time \
  --target='2026-05-07 02:13:00+03' \
  restore

Bu komutun gerçek bir incident’te ilk kez çalıştırılması felakettir. Provayı önceden yapın — adımlar runbook’a yazılsın.

Saklama

Repository’deki kullanılmayan yedeklerin temizliği expire komutuyla:

pgbackrest --stanza=main expire

repo1-retention-full=4 ile son 4 full yedek tutuluyor; daha eskileri (ve onlara bağlı diff/incr’ler) otomatik temizleniyor.

Sonuç

Schema kopyalamak veya küçük bir tabloyu taşımak için pg_dump hâlâ doğru araç. Ama PITR isteyen herhangi bir sistemde yedek yazılımı pgBackRest (veya barman, ya da veritabanı sağlayıcının kendi aracı) olmalı. Backup’ın test edilmediği anda “backup’ım var” demek yalan söylemenin sofistike bir yoludur.