AWS RDS Otomatik Yedekleme ve Geri Yükleme Rehberi

Veritabanı yedeklemesi konusunda “nasılsa AWS halleder” diye düşünüp sonra gece 2’de panik yaşayan sysadmin sayısı az değildir. RDS kullanıyorsunuz, otomatik yedekleme açık, her şey yolunda gibi görünüyor. Ama gerçek bir disaster anında geri yükleme sürecini hiç test ettiniz mi? Hangi parametrelerin ne anlama geldiğini biliyor musunuz? Bu yazıda RDS otomatik yedekleme mekanizmasını sıfırdan ele alacağız, geri yükleme senaryolarını gerçek örneklerle inceleyeceğiz.

RDS Otomatik Yedekleme Nasıl Çalışır?

AWS RDS’in otomatik yedekleme sistemi iki temel bileşenden oluşur: automated backups ve DB snapshots. Bunları birbirine karıştırmak çok yaygın bir hata.

Otomatik yedeklemeler, RDS tarafından her gün belirlediğiniz bir zaman aralığında alınır. Bu yedekler S3’te saklanır ama normal S3 bucket’larınızda göremezsiniz, AWS tarafından yönetilen dahili bir altyapıda tutulurlar. Bu yedeklerin en güzel özelliği point-in-time recovery (PITR) desteği sunmasıdır. Transaction logları sürekli olarak S3’e yazıldığı için teorik olarak son 5 dakikaya kadar herhangi bir ana geri dönebilirsiniz.

DB Snapshots ise kullanıcı tarafından manuel olarak ya da AWS Backup gibi servisler aracılığıyla alınan yedeklerdir. Bunlar otomatik yedekleme periyodundan bağımsızdır ve siz silmediğiniz sürece kalırlar.

Retention period yani saklama süresi 0 ile 35 gün arasında ayarlanabilir. 0 yapmak otomatik yedeklemeyi tamamen kapatır ki bunu production ortamında sakın yapmayın.

AWS CLI ile Mevcut Yedek Durumunu Kontrol Etmek

Önce elimizde ne var görelim. Hangi instance’ların yedekleme açık, hangi zaman aralıklarında yedek alınıyor, retention period ne kadar?

# Tüm RDS instance'larının yedekleme bilgilerini listele
aws rds describe-db-instances 
  --query 'DBInstances[*].{
    DBIdentifier:DBInstanceIdentifier,
    BackupRetention:BackupRetentionPeriod,
    BackupWindow:PreferredBackupWindow,
    Status:DBInstanceStatus
  }' 
  --output table
# Belirli bir instance için otomatik yedekleri listele
aws rds describe-db-instance-automated-backups 
  --db-instance-identifier prod-postgres-01 
  --query 'DBInstanceAutomatedBackups[*].{
    DBId:DBInstanceIdentifier,
    RestorableFrom:RestoreWindow.EarliestTime,
    RestorableTo:RestoreWindow.LatestTime,
    AllocatedStorage:AllocatedStorage,
    Engine:Engine
  }' 
  --output table

Bu komutun çıktısında RestorableFrom ve RestorableTo alanlarına dikkat edin. Bu aralık dışına düşen bir zamana geri dönemezsiniz.

# Manuel snapshotları listele
aws rds describe-db-snapshots 
  --db-instance-identifier prod-postgres-01 
  --snapshot-type manual 
  --query 'DBSnapshots[*].{
    SnapshotId:DBSnapshotIdentifier,
    CreateTime:SnapshotCreateTime,
    Status:Status,
    StorageGB:AllocatedStorage
  }' 
  --output table

Otomatik Yedekleme Ayarlarını Yapılandırmak

Yeni bir RDS instance oluştururken ya da mevcut birini güncellerken yedekleme ayarlarını doğru yapmak kritik. CLI üzerinden yapalım:

# Mevcut instance'ın yedekleme ayarlarını güncelle
aws rds modify-db-instance 
  --db-instance-identifier prod-postgres-01 
  --backup-retention-period 14 
  --preferred-backup-window "02:00-03:00" 
  --preferred-maintenance-window "mon:04:00-mon:05:00" 
  --apply-immediately

# Komut parametreleri:
# --backup-retention-period: Kaç gün yedek saklanacak (1-35)
# --preferred-backup-window: UTC cinsinden yedekleme penceresi
# --preferred-maintenance-window: Bakım penceresi (yedeklemeyle çakışmamalı)
# --apply-immediately: Değişikliği hemen uygula, maintenance window bekleme

Burada önemli bir nokta: --preferred-backup-window ile --preferred-maintenance-window çakışmamalı. Maintenance sırasında instance kısa süreliğine unavailable olabilir ve bu yedek penceresine denk gelirse sorun çıkar.

Türkiye saatiyle düşünecek olursak (UTC+3), 02:00-03:00 UTC yedekleme penceresi sabah 05:00-06:00’a denk gelir. Production trafiğinin en düşük olduğu saati tercih etmek mantıklı.

Point-in-Time Recovery: Gerçek Senaryo

Diyelim ki geliştirici arkadaşlardan biri saat 14:35’te DELETE FROM orders WHERE user_id = 5 yerine yanlışlıkla DELETE FROM orders; çalıştırdı. Fark 14:50’de fark edildi. Ne yapıyoruz?

PITR ile 14:34’e yani silme işleminden 1 dakika öncesine gidebiliriz. Ama dikkat: RDS’de restore işlemi mevcut instance’ı ezmez, her zaman yeni bir instance oluşturur. Bu hem güvenlik hem de esneklik açısından iyi bir tasarım.

# Belirli bir zamana geri yükle
aws rds restore-db-instance-to-point-in-time 
  --source-db-instance-identifier prod-postgres-01 
  --target-db-instance-identifier prod-postgres-01-recovery-1435 
  --restore-time "2024-01-15T11:34:00Z" 
  --db-instance-class db.r6g.large 
  --no-multi-az 
  --publicly-accessible false

# Komut parametreleri:
# --source-db-instance-identifier: Kaynak instance adı
# --target-db-instance-identifier: Yeni oluşturulacak instance adı
# --restore-time: UTC cinsinden geri dönmek istediğiniz an
# --db-instance-class: Recovery instance'ın boyutu (küçültebilirsiniz)
# --no-multi-az: Recovery sırasında multi-az kapatılabilir, maliyet düşer

Recovery instance’ın ayağa kalkması için birkaç dakika beklemeniz gerekecek. Instance durumunu takip edin:

# Recovery instance'ın durumunu izle
watch -n 30 'aws rds describe-db-instances 
  --db-instance-identifier prod-postgres-01-recovery-1435 
  --query "DBInstances[0].DBInstanceStatus" 
  --output text'

Instance available durumuna geçince endpoint’ini alıp veritabanına bağlanın, silinen tablonun hala yerinde olduğunu doğrulayın. Sonra production ortamınıza veriyi aktarmak için pg_dump ya da mysqldump kullanabilirsiniz.

# Recovery instance endpoint'ini al
RECOVERY_ENDPOINT=$(aws rds describe-db-instances 
  --db-instance-identifier prod-postgres-01-recovery-1435 
  --query "DBInstances[0].Endpoint.Address" 
  --output text)

echo "Recovery endpoint: $RECOVERY_ENDPOINT"

# PostgreSQL için sadece ilgili tabloyu dump al
pg_dump 
  -h $RECOVERY_ENDPOINT 
  -U admin 
  -d proddb 
  -t orders 
  --data-only 
  -f orders_recovery_20240115.sql

Veriyi aldıktan sonra production’a import edin ve recovery instance’ı silin. Recovery instance’ı ayakta bırakmak para yakıyor.

# İşimiz bitti, recovery instance'ı sil
aws rds delete-db-instance 
  --db-instance-identifier prod-postgres-01-recovery-1435 
  --skip-final-snapshot

Snapshot’tan Geri Yükleme

Bazen PITR değil de belirli bir snapshot’tan restore etmeniz gerekebilir. Örneğin büyük bir deployment öncesi manuel snapshot alıp deployment sonrası sorun çıkarsa o snapshot’a dönmek yaygın bir pratiktir.

# Deployment öncesi manuel snapshot al
aws rds create-db-snapshot 
  --db-instance-identifier prod-mysql-01 
  --db-snapshot-identifier prod-mysql-01-before-deploy-v2-3-1

# Snapshot tamamlanana kadar bekle
aws rds wait db-snapshot-completed 
  --db-snapshot-identifier prod-mysql-01-before-deploy-v2-3-1

echo "Snapshot hazır, deployment başlayabilir"

Deployment sonrası bir şeyler ters giderse:

# Snapshot'tan yeni instance oluştur
aws rds restore-db-instance-from-db-snapshot 
  --db-instance-identifier prod-mysql-01-rollback 
  --db-snapshot-identifier prod-mysql-01-before-deploy-v2-3-1 
  --db-instance-class db.r6g.xlarge 
  --no-publicly-accessible 
  --vpc-security-group-ids sg-0abc123def456789 
  --db-subnet-group-name prod-subnet-group

Bu yöntemde dikkat etmeniz gereken nokta: snapshot’tan restore ettiğinizde instance’ın parameter group’u ve option group’u default değerlere dönebilir. Production ayarlarınızı mutlaka yeniden uygulayın.

Cross-Region Backup Stratejisi

Bölgesel bir AWS kesintisine karşı hazırlıklı olmak istiyorsanız snapshot’larınızı başka region’lara kopyalamanız gerekir. Otomatik yedekler varsayılan olarak sadece bulundukları region’da tutulur.

# Snapshot'ı başka region'a kopyala
aws rds copy-db-snapshot 
  --source-db-snapshot-identifier arn:aws:rds:eu-west-1:123456789:snapshot:prod-postgres-01-snapshot 
  --target-db-snapshot-identifier prod-postgres-01-snapshot-copy 
  --kms-key-id arn:aws:kms:eu-central-1:123456789:key/mrk-abc123 
  --region eu-central-1 
  --copy-tags

# Komut parametreleri:
# --source-db-snapshot-identifier: Kaynak snapshot'ın ARN'ı (cross-region için tam ARN gerekli)
# --target-db-snapshot-identifier: Hedef region'daki yeni isim
# --kms-key-id: Hedef region'daki KMS key (şifreleme için)
# --copy-tags: Tag'leri de kopyala

Bu işlemi otomatize etmek için bir Lambda fonksiyonu veya basit bir cron job kullanabilirsiniz. İşte haftalık cross-region backup için bir bash scripti:

#!/bin/bash
# weekly-cross-region-backup.sh
# Crontab: 0 3 * * 0 /opt/scripts/weekly-cross-region-backup.sh

SOURCE_REGION="eu-west-1"
TARGET_REGION="eu-central-1"
ACCOUNT_ID="123456789012"
KMS_KEY_ID="arn:aws:kms:eu-central-1:${ACCOUNT_ID}:key/mrk-abc123"
INSTANCES=("prod-postgres-01" "prod-mysql-01" "prod-aurora-cluster")
DATE_SUFFIX=$(date +%Y%m%d)
RETENTION_DAYS=30

for INSTANCE in "${INSTANCES[@]}"; do
  echo "Processing: $INSTANCE"

  # Önce local snapshot al
  SNAPSHOT_ID="${INSTANCE}-weekly-${DATE_SUFFIX}"

  aws rds create-db-snapshot 
    --db-instance-identifier "$INSTANCE" 
    --db-snapshot-identifier "$SNAPSHOT_ID" 
    --region "$SOURCE_REGION" 
    --tags Key=Type,Value=weekly Key=Date,Value="$DATE_SUFFIX" 
    > /dev/null

  # Snapshot hazır olana kadar bekle
  aws rds wait db-snapshot-completed 
    --db-snapshot-identifier "$SNAPSHOT_ID" 
    --region "$SOURCE_REGION"

  SOURCE_ARN="arn:aws:rds:${SOURCE_REGION}:${ACCOUNT_ID}:snapshot:${SNAPSHOT_ID}"

  # Cross-region kopyala
  aws rds copy-db-snapshot 
    --source-db-snapshot-identifier "$SOURCE_ARN" 
    --target-db-snapshot-identifier "${SNAPSHOT_ID}-dr" 
    --kms-key-id "$KMS_KEY_ID" 
    --region "$TARGET_REGION" 
    --copy-tags 
    > /dev/null

  echo "Copied $INSTANCE snapshot to $TARGET_REGION"

  # Eski cross-region snapshotları temizle
  OLD_SNAPSHOTS=$(aws rds describe-db-snapshots 
    --db-instance-identifier "$INSTANCE" 
    --snapshot-type manual 
    --region "$TARGET_REGION" 
    --query "DBSnapshots[?SnapshotCreateTime<='$(date -d "-${RETENTION_DAYS} days" --iso-8601=seconds)'].DBSnapshotIdentifier" 
    --output text)

  for OLD_SNAP in $OLD_SNAPSHOTS; do
    aws rds delete-db-snapshot 
      --db-snapshot-identifier "$OLD_SNAP" 
      --region "$TARGET_REGION"
    echo "Deleted old snapshot: $OLD_SNAP"
  done

done

echo "Weekly cross-region backup completed"

Yedekleme Durumunu Otomatik Monitoring

Yedekleme ayarlarını yapıp bırakmak yetmez. Yedeklerin düzenli alındığını, retention’ın doğru ayarlı olduğunu ve herhangi bir instance’ın gözden kaçmadığını kontrol eden bir monitoring scripti hazırlayalım:

#!/bin/bash
# check-rds-backup-compliance.sh
# Tüm RDS instance'larının yedekleme uyumluluğunu kontrol eder

MIN_RETENTION_DAYS=7
ALERT_EMAIL="[email protected]"
ISSUES=()

# Tüm instance'ları çek
INSTANCES=$(aws rds describe-db-instances 
  --query 'DBInstances[*].DBInstanceIdentifier' 
  --output text)

for INSTANCE in $INSTANCES; do
  RETENTION=$(aws rds describe-db-instances 
    --db-instance-identifier "$INSTANCE" 
    --query 'DBInstances[0].BackupRetentionPeriod' 
    --output text)

  MULTI_AZ=$(aws rds describe-db-instances 
    --db-instance-identifier "$INSTANCE" 
    --query 'DBInstances[0].MultiAZ' 
    --output text)

  # Yedekleme kapalı mı?
  if [ "$RETENTION" -eq 0 ]; then
    ISSUES+=("KRITIK: $INSTANCE - Otomatik yedekleme KAPALI!")
  # Yedekleme süresi yetersiz mi?
  elif [ "$RETENTION" -lt "$MIN_RETENTION_DAYS" ]; then
    ISSUES+=("UYARI: $INSTANCE - Retention $RETENTION gun (minimum $MIN_RETENTION_DAYS gun olmali)")
  fi

  # Son 24 satte snapshot var mi?
  RECENT_BACKUP=$(aws rds describe-db-instance-automated-backups 
    --db-instance-identifier "$INSTANCE" 
    --query "DBInstanceAutomatedBackups[?RestoreWindow.LatestTime>='$(date -u -d '24 hours ago' --iso-8601=seconds)'].DBInstanceIdentifier" 
    --output text 2>/dev/null)

  if [ -z "$RECENT_BACKUP" ]; then
    ISSUES+=("UYARI: $INSTANCE - Son 24 saatte otomatik yedek bulunamadi")
  fi

  echo "Kontrol edildi: $INSTANCE (Retention: $RETENTION gun, MultiAZ: $MULTI_AZ)"
done

# Sorun varsa alert gönder
if [ ${#ISSUES[@]} -gt 0 ]; then
  echo "=== YEDEKLEME SORUNLARI ==="
  printf '%sn' "${ISSUES[@]}"

  # SNS üzerinden alert gönder
  MESSAGE=$(printf '%sn' "${ISSUES[@]}")
  aws sns publish 
    --topic-arn "arn:aws:sns:eu-west-1:123456789012:ops-alerts" 
    --subject "RDS Yedekleme Uyumluluk Sorunu" 
    --message "$MESSAGE"
else
  echo "Tüm instance'lar yedekleme politikasına uygun."
fi

Aurora için Özel Durumlar

Aurora kullanıyorsanız yedekleme mekanizması biraz farklı çalışır ve çok daha iyidir. Aurora, veriyi zaten 3 AZ’da 6 kopya olarak tutuğu için storage seviyesinde çok daha dayanıklıdır. PITR için minimum restore zamanı genellikle 1 dakikaya kadar iner.

Aurora’da cluster snapshot’larını yönetirken:

# Aurora cluster snapshot al
aws rds create-db-cluster-snapshot 
  --db-cluster-identifier prod-aurora-cluster 
  --db-cluster-snapshot-identifier prod-aurora-cluster-snapshot-$(date +%Y%m%d%H%M)

# Aurora cluster snapshot'tan restore et
aws rds restore-db-cluster-from-snapshot 
  --db-cluster-identifier prod-aurora-cluster-recovery 
  --snapshot-identifier prod-aurora-cluster-snapshot-20240115 
  --engine aurora-postgresql 
  --engine-version 15.4 
  --db-subnet-group-name prod-subnet-group 
  --vpc-security-group-ids sg-0abc123def456789

# Cluster ayağa kalktıktan sonra instance ekle
aws rds create-db-instance 
  --db-instance-identifier prod-aurora-cluster-recovery-instance-1 
  --db-cluster-identifier prod-aurora-cluster-recovery 
  --db-instance-class db.r6g.large 
  --engine aurora-postgresql

Geri Yükleme Testlerini Otomatize Etmek

Yedek alıyorsunuz ama hiç test ettiniz mi? “Yedeklerim var” demekle “yedeklerimden geri dönebilirim” demek farklı şeyler. Ayda bir otomatik restore testi yapan bir sistem kurun:

#!/bin/bash
# monthly-restore-test.sh

INSTANCE="prod-postgres-01"
TEST_INSTANCE="restore-test-$(date +%Y%m)"
RESTORE_TIME=$(date -u -d '1 hour ago' --iso-8601=seconds)

echo "Restore testi başlıyor: $RESTORE_TIME anına geri dönülüyor"

# Test instance oluştur
aws rds restore-db-instance-to-point-in-time 
  --source-db-instance-identifier "$INSTANCE" 
  --target-db-instance-identifier "$TEST_INSTANCE" 
  --restore-time "$RESTORE_TIME" 
  --db-instance-class db.t3.medium 
  --no-multi-az 
  --no-publicly-accessible

# Available olana kadar bekle (max 30 dakika)
timeout 1800 aws rds wait db-instance-available 
  --db-instance-identifier "$TEST_INSTANCE"

if [ $? -eq 0 ]; then
  echo "BASARILI: Restore testi geçti"

  # Basit bir connectivity testi yap
  TEST_ENDPOINT=$(aws rds describe-db-instances 
    --db-instance-identifier "$TEST_INSTANCE" 
    --query "DBInstances[0].Endpoint.Address" 
    --output text)

  # pg_isready ile bağlantıyı doğrula
  pg_isready -h "$TEST_ENDPOINT" -U admin -d proddb
  if [ $? -eq 0 ]; then
    echo "Veritabanı bağlantısı doğrulandı"
    aws sns publish 
      --topic-arn "arn:aws:sns:eu-west-1:123456789012:ops-alerts" 
      --subject "Aylık RDS Restore Testi: BASARILI" 
      --message "Instance: $INSTANCE, Test zamanı: $(date)"
  fi
else
  echo "HATA: Restore testi başarısız oldu!"
  aws sns publish 
    --topic-arn "arn:aws:sns:eu-west-1:123456789012:ops-alerts" 
    --subject "Aylık RDS Restore Testi: BASARISIZ" 
    --message "Instance: $INSTANCE için restore testi başarısız oldu. Manuel inceleme gerekiyor."
fi

# Test instance'ı temizle
aws rds delete-db-instance 
  --db-instance-identifier "$TEST_INSTANCE" 
  --skip-final-snapshot

echo "Test instance silindi"

Dikkat Edilmesi Gereken Noktalar

Gerçek hayatta sık karşılaşılan tuzaklardan bahsedelim:

RDS instance’ı silince otomatik yedekler ne olur? Instance’ı sildiğinizde otomatik yedekler de gider. Ama silme sırasında “final snapshot” alırsanız o kalır. Production’da bir instance’ı silerken asla --skip-final-snapshot kullanmayın.

Parameter group restore sonrası sıfırlanır. Restore işlemi tamamlandıktan sonra instance’ın parameter group’unu kontrol edin ve production ayarlarınızı tekrar uygulayın. Aksi halde PostgreSQL max_connections ya da MySQL innodb_buffer_pool_size gibi kritik parametreler default değerlerde kalır.

Security group’lar restore sonrası default’a döner. Restore ettiğiniz instance’ın security group ayarları kaynak instance ile aynı olmayabilir. Özellikle VPC güvenlik gruplarını restore sonrası mutlaka kontrol edin.

Şifreli RDS’i restore ederken KMS key erişimi gerekir. Eğer cross-account restore yapıyorsanız ya da KMS key politikaları değiştiyse restore işlemi başarısız olur. KMS key erişim haklarını önceden doğrulayın.

Restore sırasında maliyet artışına dikkat. Recovery instance ayakta olduğu sürece para ödersiniz. Testi bitirdikten hemen sonra instance’ı silin. Büyük instance tipiyle yaptığınız uzun restore testleri bütçenizi etkileyebilir.

Sonuç

RDS otomatik yedekleme sistemi güçlü ve büyük ölçüde yönetimini AWS’e bırakabildiğiniz bir yapı. Ama “AWS halleder” mentalitesiyle gözlerinizi kapatmak doğru değil. Retention period’un doğru ayarlı olduğunu düzenli kontrol edin, cross-region yedekleme stratejinizi belirleyin, ve en önemlisi restore testlerini rutin hale getirin.

Gece 2’de production veritabanınızı kurtarmanız gerektiğinde soğukkanlı kalabilmenizin tek yolu o prosedürü daha önce sakin bir ortamda denemiş olmaktır. Restore scriptlerini yazdınız, test ettiniz, çalışır durumda olduğunu doğruladınız. O zaman gerçek bir kriz anında paniğe kapılmadan işinizi yaparsınız.

Yedekleme bir sigorta poliçesidir. Sigorta poliçesini imzaladıktan sonra da zaman zaman kapsamını gözden geçirip güncel tutmak gerekir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir