PostgreSQL Yedekleme Yöntemleri: pg_dump ve pg_basebackup Kullanımı

Veritabanı yönetiminde en kritik konulardan biri yedekleme stratejisidir. PostgreSQL bu konuda bize iki temel araç sunar: pg_dump ve pg_basebackup. Her ikisi de güçlü araçlar olmakla birlikte, farklı senaryolar için tasarlanmışlardır. Hangisini ne zaman kullanacağınızı bilmek, felaket anında saatlerce süren veri kaybı ile dakikalar içinde recovery yapabilmek arasındaki farkı belirler. Bu yazıda her iki aracı da derinlemesine inceleyeceğiz, gerçek dünya senaryolarıyla pratik kullanım örnekleri vereceğiz.

pg_dump: Mantıksal Yedekleme

pg_dump, PostgreSQL’in mantıksal yedekleme aracıdır. Veritabanının yapısını (şema) ve verilerini SQL komutları veya özel formatlarda dışa aktarır. Çalışan bir veritabanından tutarlı bir yedek alabilmesi, onu üretim ortamları için son derece kullanışlı kılar.

pg_dump Nasıl Çalışır?

pg_dump, yedekleme sırasında veritabanını kilitlemez. MVCC (Multi-Version Concurrency Control) mekanizmasını kullanarak işlem başladığı andaki veri görüntüsünü alır. Bu sayede kullanıcılar veritabanını kullanmaya devam ederken siz yedek alabilirsiniz.

Temel Kullanım

En basit haliyle bir veritabanını yedeklemek:

pg_dump -U postgres -d mydb -f /backup/mydb.sql

Ancak production ortamlarında bu kadar basit bırakmayın. Şu parametreleri mutlaka öğrenin:

-U: Bağlanacak kullanıcı adı -h: Veritabanı sunucusu adresi -p: Port numarası (varsayılan 5432) -d: Yedeklenecek veritabanı adı -f: Çıktı dosyasının yolu -F: Çıktı formatı (p=plain, c=custom, d=directory, t=tar) -j: Paralel iş sayısı (directory formatında kullanılır) -v: Verbose mod, işlem detaylarını gösterir -Z: Sıkıştırma seviyesi (0-9)

Format Seçimi: Hangisini Kullanmalısınız?

Plain format (-Fp): Düz SQL dosyası üretir. İnsan tarafından okunabilir ama büyük veritabanlarında çok yer kaplar.

Custom format (-Fc): Sıkıştırılmış, pg_restore ile seçici geri yükleme yapılabilir. Çoğu senaryo için önerilen format budur.

Directory format (-Fd): Her tablo için ayrı dosya oluşturur, paralel yedekleme/geri yükleme mümkündür.

Tar format (-Ft): Taşınabilir ama sınırlı kullanım alanı var.

# Custom format ile yedekleme (önerilen)
pg_dump -U postgres -d mydb -Fc -Z 9 -f /backup/mydb_$(date +%Y%m%d_%H%M%S).dump

# Directory format ile paralel yedekleme (büyük veritabanları için)
pg_dump -U postgres -d mydb -Fd -j 4 -f /backup/mydb_dir_$(date +%Y%m%d)

Gerçek Dünya Senaryosu 1: E-ticaret Veritabanı Günlük Yedeği

Diyelim ki 50 GB’lık bir e-ticaret veritabanınız var. Her gece 02:00’de tam yedek almak ve 7 gün tutmak istiyorsunuz:

#!/bin/bash
# /usr/local/bin/pg_backup_daily.sh

BACKUP_DIR="/backup/postgresql"
DB_NAME="ecommerce_db"
DB_USER="postgres"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.dump"
LOG_FILE="/var/log/pg_backup.log"

# Backup dizini yoksa oluştur
mkdir -p ${BACKUP_DIR}

echo "[$(date)] Yedekleme başlıyor: ${DB_NAME}" >> ${LOG_FILE}

# Yedekleme al
pg_dump -U ${DB_USER} 
        -d ${DB_NAME} 
        -Fc 
        -Z 6 
        -v 
        -f ${BACKUP_FILE} 2>> ${LOG_FILE}

if [ $? -eq 0 ]; then
    echo "[$(date)] Yedekleme başarılı: ${BACKUP_FILE}" >> ${LOG_FILE}
    # Eski yedekleri temizle
    find ${BACKUP_DIR} -name "${DB_NAME}_*.dump" -mtime +${RETENTION_DAYS} -delete
    echo "[$(date)] Eski yedekler temizlendi (${RETENTION_DAYS} günden eski)" >> ${LOG_FILE}
else
    echo "[$(date)] HATA: Yedekleme başarısız!" >> ${LOG_FILE}
    # Burada alert/bildirim sisteminizi çağırabilirsiniz
    exit 1
fi

Bu scripti crontab’a ekleyin:

# crontab -e
0 2 * * * /usr/local/bin/pg_backup_daily.sh

Seçici Yedekleme: Sadece İhtiyacınız Olanı Alın

pg_dump‘ın güzel özelliklerinden biri seçici yedekleme yapabilmesidir:

# Sadece belirli tabloları yedekle
pg_dump -U postgres -d mydb -Fc 
        -t orders 
        -t order_items 
        -t customers 
        -f /backup/sales_tables.dump

# Belirli şemayı yedekle
pg_dump -U postgres -d mydb -Fc 
        -n public 
        -f /backup/public_schema.dump

# Sadece şema yapısını al, veri olmadan
pg_dump -U postgres -d mydb -s 
        -f /backup/schema_only.sql

# Sadece veriyi al, şema olmadan
pg_dump -U postgres -d mydb -a 
        -f /backup/data_only.sql

pg_restore ile Geri Yükleme

Custom veya directory formatında alınan yedekleri pg_restore ile geri yüklersiniz:

# Tam geri yükleme
pg_restore -U postgres 
           -d mydb_restored 
           -v 
           /backup/mydb_20240115_020000.dump

# Paralel geri yükleme (hızlı!)
pg_restore -U postgres 
           -d mydb_restored 
           -j 8 
           -v 
           /backup/mydb_20240115_020000.dump

# Sadece belirli tabloları geri yükle
pg_restore -U postgres 
           -d mydb 
           -t orders 
           /backup/mydb_20240115_020000.dump

pg_dumpall: Tüm Cluster’ı Yedekleme

pg_dump tek bir veritabanını yedekler. Global nesneleri (roller, tablespace’ler) ve tüm veritabanlarını yedeklemek için pg_dumpall kullanın:

# Tüm cluster'ı yedekle (globals dahil)
pg_dumpall -U postgres -f /backup/all_databases_$(date +%Y%m%d).sql

# Sadece global nesneleri yedekle (roller, tablespace'ler)
pg_dumpall -U postgres -g -f /backup/globals_$(date +%Y%m%d).sql

pg_basebackup: Fiziksel Yedekleme

pg_basebackup, PostgreSQL cluster’ının fiziksel bir kopyasını alır. Dosya sistemi seviyesinde çalışır ve genellikle Point-in-Time Recovery (PITR) ve streaming replication kurulumlarında kullanılır.

pg_dump’tan Farkı Nedir?

pg_dump verileri SQL veya özel formatta dışa aktarırken, pg_basebackup PostgreSQL’in data dizininin birebir kopyasını alır. Bu kopya, WAL (Write-Ahead Log) dosyalarıyla birleştirildiğinde herhangi bir noktaya geri dönmeyi mümkün kılar.

pg_basebackup‘ın avantajları:

  • Çok büyük veritabanlarında pg_dump‘tan çok daha hızlı
  • PITR için gerekli altyapıyı sağlar
  • Streaming replication standby sunucu kurulumunda kullanılır
  • Tüm cluster’ı (tüm veritabanları dahil) tek seferde yedekler

Dezavantajları:

  • pg_dump‘ın aksine seçici yedekleme yapamazsınız
  • Aynı büyük versiyon (major version) PostgreSQL ile restore edilmesi gerekir
  • WAL arşivleme olmadan alındığında yalnızca o anki tutarlı durumu yansıtır

postgresql.conf Hazırlığı

pg_basebackup kullanmadan önce sunucunuzun WAL arşivlemeye hazır olması gerekir:

# postgresql.conf'ta şu ayarları yapın
wal_level = replica
archive_mode = on
archive_command = 'cp %p /archive/wal/%f'
max_wal_senders = 3

Ayrıca pg_hba.conf‘a replication erişimi ekleyin:

# pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   replication     postgres                                peer
host    replication     replicator      192.168.1.0/24          md5

Temel Kullanım

# Basit base backup
pg_basebackup -U postgres 
              -D /backup/basebackup_$(date +%Y%m%d) 
              -Fp 
              -Xs 
              -P

# Tar formatında, sıkıştırılmış
pg_basebackup -U postgres 
              -D /backup/basebackup_$(date +%Y%m%d) 
              -Ft 
              -z 
              -Xs 
              -P 
              -v

Önemli parametreler:

-D: Yedek dosyalarının yazılacağı dizin -F: Format, p=plain (dizin), t=tar -X: WAL dosyalarını dahil etme yöntemi, s=stream (önerilen), f=fetch -z: Gzip sıkıştırma (tar formatıyla birlikte) -P: İlerleme durumunu göster -R: recovery.conf dosyasını otomatik oluştur (standby kurulumu için) -C: Replication slot oluştur –checkpoint: fast veya spread, hızlı checkpoint ister

Gerçek Dünya Senaryosu 2: Standby Sunucu Kurulumu

Streaming replication için standby sunucuya base backup alıp taşıma:

#!/bin/bash
# Standby sunucuda çalıştırılacak script
# /usr/local/bin/setup_standby.sh

MASTER_HOST="192.168.1.10"
REPLICATION_USER="replicator"
PGDATA="/var/lib/postgresql/14/main"
BACKUP_DIR="/tmp/basebackup"

# Mevcut data dizinini temizle (DİKKATLİ OLUN!)
systemctl stop postgresql
rm -rf ${PGDATA}/*

echo "Base backup alınıyor..."
pg_basebackup -h ${MASTER_HOST} 
              -U ${REPLICATION_USER} 
              -D ${PGDATA} 
              -Fp 
              -Xs 
              -R 
              -P 
              -v

# -R parametresi otomatik olarak standby.signal ve
# postgresql.auto.conf dosyalarını oluşturur

# İzinleri düzelt
chown -R postgres:postgres ${PGDATA}
chmod 700 ${PGDATA}

echo "Standby sunucu hazır. PostgreSQL başlatılıyor..."
systemctl start postgresql

Gerçek Dünya Senaryosu 3: PITR ile Belirli Bir Zamana Dönme

Üretimde bir geliştirici yanlışlıkla kritik bir tabloyu truncate etti. Saat 14:35’te oldu. Siz günlük base backup ve WAL arşivleme yapıyorsunuz. 14:34’e dönmeniz gerekiyor:

# 1. Mevcut PostgreSQL servisini durdur
systemctl stop postgresql

# 2. Yeni bir recovery dizini oluştur
mkdir -p /recovery/data

# 3. Base backup'ı bu dizine aç
tar -xzf /backup/basebackup_20240115/base.tar.gz -C /recovery/data/
tar -xzf /backup/basebackup_20240115/pg_wal.tar.gz -C /recovery/data/pg_wal/

# 4. recovery.conf yerine postgresql.conf'a recovery ayarlarını ekle
# (PostgreSQL 12+)
cat >> /recovery/data/postgresql.conf << EOF
restore_command = 'cp /archive/wal/%f %p'
recovery_target_time = '2024-01-15 14:34:00'
recovery_target_action = 'promote'
EOF

# 5. recovery.signal dosyası oluştur (PostgreSQL 12+)
touch /recovery/data/recovery.signal

# 6. İzinleri düzelt
chown -R postgres:postgres /recovery/data
chmod 700 /recovery/data

# 7. PostgreSQL'i recovery modunda başlat
# PGDATA'yı geçici olarak değiştir
PGDATA=/recovery/data postgresql -D /recovery/data

# Log'ları takip ederek recovery'nin tamamlanmasını bekleyin
tail -f /recovery/data/log/postgresql-*.log

pg_basebackup ile Düzenli Yedekleme Scripti

#!/bin/bash
# /usr/local/bin/basebackup_weekly.sh
# Her Pazar gecesi çalışacak haftalık base backup

BACKUP_BASE="/backup/basebackup"
RETENTION_WEEKS=4
DATE=$(date +%Y%m%d)
BACKUP_DIR="${BACKUP_BASE}/backup_${DATE}"
LOG_FILE="/var/log/pg_basebackup.log"

echo "[$(date)] Base backup başlıyor..." >> ${LOG_FILE}

mkdir -p ${BACKUP_DIR}

pg_basebackup -U postgres 
              -D ${BACKUP_DIR} 
              -Ft 
              -z 
              -Xs 
              -P 
              -v 
              --checkpoint=fast 2>> ${LOG_FILE}

if [ $? -eq 0 ]; then
    echo "[$(date)] Base backup başarılı: ${BACKUP_DIR}" >> ${LOG_FILE}
    
    # Dosya boyutunu logla
    BACKUP_SIZE=$(du -sh ${BACKUP_DIR} | cut -f1)
    echo "[$(date)] Yedek boyutu: ${BACKUP_SIZE}" >> ${LOG_FILE}
    
    # Eski yedekleri temizle
    ls -dt ${BACKUP_BASE}/backup_* | tail -n +$((RETENTION_WEEKS + 1)) | xargs rm -rf
    echo "[$(date)] Eski yedekler temizlendi" >> ${LOG_FILE}
else
    echo "[$(date)] HATA: Base backup başarısız!" >> ${LOG_FILE}
    exit 1
fi

İki Yöntemi Birlikte Kullanma: Kapsamlı Yedekleme Stratejisi

Gerçek dünyada bu iki yöntemi birbirinin alternatifi olarak değil, tamamlayıcı olarak kullanmalısınız.

Önerilen Strateji

  • Her gece: pg_dump ile kritik veritabanlarının mantıksal yedeğini alın. Hızlı geri yükleme ve seçici recovery için idealdir.
  • Her hafta: pg_basebackup ile tam fiziksel yedek alın. PITR altyapısını destekler.
  • Sürekli: WAL arşivleme aktif olsun. Bu sayede haftalık backup arasındaki herhangi bir noktaya dönebilirsiniz.
# Kapsamlı yedekleme stratejisi için crontab
# Her gece 01:00'de mantıksal yedek
0 1 * * * /usr/local/bin/pg_backup_daily.sh

# Her Pazar 03:00'te fiziksel yedek
0 3 * * 0 /usr/local/bin/basebackup_weekly.sh

# WAL arşivleme postgresql.conf'ta aktif (sürekli)

Yedeklerin Bütünlüğünü Test Etme

Yedek almak yetmez, test etmek zorundasınız. Bu adımı atlayan birçok sysadmin’in kritik anlarda “yedek bozuk” sürprizi yaşadığını gördüm:

#!/bin/bash
# /usr/local/bin/backup_verify.sh
# Her hafta yedeklerin sağlamlığını test et

BACKUP_FILE=$(ls -t /backup/postgresql/*.dump | head -1)
TEST_DB="backup_test_$(date +%Y%m%d)"
LOG_FILE="/var/log/backup_verify.log"

echo "[$(date)] Yedek doğrulama başlıyor: ${BACKUP_FILE}" >> ${LOG_FILE}

# Test veritabanı oluştur
psql -U postgres -c "CREATE DATABASE ${TEST_DB};" 2>> ${LOG_FILE}

# Yedeği geri yükle
pg_restore -U postgres 
           -d ${TEST_DB} 
           -v 
           ${BACKUP_FILE} 2>> ${LOG_FILE}

if [ $? -eq 0 ]; then
    echo "[$(date)] Yedek doğrulama BAŞARILI" >> ${LOG_FILE}
    # Temel sorgu testi
    TABLE_COUNT=$(psql -U postgres -d ${TEST_DB} -t -c 
        "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';")
    echo "[$(date)] Geri yüklenen tablo sayısı: ${TABLE_COUNT}" >> ${LOG_FILE}
else
    echo "[$(date)] HATA: Yedek doğrulama BAŞARISIZ!" >> ${LOG_FILE}
fi

# Test veritabanını temizle
psql -U postgres -c "DROP DATABASE ${TEST_DB};" 2>> ${LOG_FILE}

echo "[$(date)] Doğrulama tamamlandı" >> ${LOG_FILE}

Uzak Sunucuya Yedekleme

Yedekleri yerel diskde tutmak single point of failure oluşturur. Uzak bir sunucuya veya nesne depolama alanına gönderin:

# rsync ile uzak sunucuya kopyalama
rsync -avz --delete 
      /backup/postgresql/ 
      backup-server:/remote/backup/postgresql/ 
      --log-file=/var/log/rsync_backup.log

# SSH üzerinden direkt pipe ile yedekleme
pg_dump -U postgres -d mydb -Fc | 
    ssh backup-user@backup-server 
    "cat > /backup/mydb_$(date +%Y%m%d).dump"

# AWS S3'e gönderme (aws cli gerekli)
pg_dump -U postgres -d mydb -Fc | 
    aws s3 cp - s3://my-bucket/postgresql/mydb_$(date +%Y%m%d).dump

Performans İpuçları

Büyük veritabanlarında yedekleme süresi kritik olabilir. Birkaç pratik ipucu:

  • Paralel yedekleme kullanın: pg_dump -Fd -j 8 ile 8 paralel iş başlatabilirsiniz. CPU core sayısını aşmayın.
  • Sıkıştırma seviyesini ayarlayın: -Z 6 genellikle iyi bir denge noktasıdır. Maksimum sıkıştırma için -Z 9 ama bu CPU yoğundur.
  • Ağ yedeklemelerinde bant genişliğini yönetin: pg_basebackup --max-rate=100M ile hız sınırı koyabilirsiniz.
  • checkpoint=fast kullanın: pg_basebackup --checkpoint=fast ile uzun checkpoint bekleme süresinden kurtulun.
  • Off-peak saatlerde çalışın: Yedekleme disk I/O yoğundur, üretim trafiğinin düşük olduğu saatlerde zamanlayın.

Sonuç

pg_dump ve pg_basebackup, birbirini tamamlayan iki güçlü araçtır. pg_dump esnekliği ve taşınabilirliği ile mantıksal yedekleme ihtiyaçlarınızı karşılar; hızlı single-table recovery, farklı PostgreSQL versiyonlarına migration ve küçük-orta ölçekli veritabanları için mükemmeldir. pg_basebackup ise büyük ölçekli ortamlar, PITR gereksinimleri ve replication kurulumları için vazgeçilmezdir.

İdeal bir yedekleme stratejisi ikisini birlikte kullanır: Günlük pg_dump, haftalık pg_basebackup ve sürekli WAL arşivleme. Bu üçlü sizi neredeyse her felaket senaryosuna karşı korur.

Son olarak, en iyi yedekleme senaryosu bile test edilmemişse değersizdir. Yedeklerinizi düzenli olarak test edin, restore prosedürlerinizi belgeleyin ve ekibinizin bu prosedürleri bildiğinden emin olun. Çünkü felaket anında “nasıl geri yükleyeceğimi tam hatırlamıyorum” demek istemezsiniz.

Yorum yapın