Warm Standby ile Felaket Kurtarma Mimarisi

Üretim ortamınız çöktüğünde saatler içinde değil, dakikalar içinde ayağa kalkabilmek istiyorsanız Warm Standby mimarisi tam da aradığınız şey. Ne Hot Standby kadar pahalı, ne de Cold Standby kadar riskli. Bu yazıda gerçek dünya senaryoları üzerinden Warm Standby’ı nasıl kuracağınızı, test edeceğinizi ve operasyonel hale getireceğinizi adım adım ele alacağız.

Warm Standby Nedir ve Neden Tercih Edilir

Felaket kurtarma stratejileri genellikle üç ana kategoriye ayrılır: Cold Standby, Warm Standby ve Hot Standby. Cold Standby’da sistemler kapalıdır, felaket anında kurulum ve yapılandırma gerekir, RTO (Recovery Time Objective) saatlerle ölçülür. Hot Standby’da ise her şey canlı çalışır, traffic anında devralınır ama maliyet iki katına çıkar.

Warm Standby tam ortada durur. Sistemler çalışır durumda ama production trafiği almaz. Veriler sürekli replike edilir. Felaket anında DNS veya load balancer seviyesinde bir yönlendirme değişikliğiyle dakikalar içinde devreye girebilirsiniz. Çoğu şirket için bu denge idealdir: RTO genellikle 15 dakika ile 1 saat arasında, RPO (Recovery Point Objective) ise dakikalar mertebesinde tutulabilir.

Gerçek dünyadan bir örnek verelim: E-ticaret platformu çalıştıran bir müşterim vardı. Black Friday’de primary datacenter’larında UPS arızası yaşandı. Hot Standby maliyetini karşılayamıyorlardı ama Warm Standby ile kurulu sistemleri 22 dakikada production trafiğini devraldı. O günkü ciro kaybı minimumda kaldı.

Mimari Bileşenler ve Tasarım Kararları

Warm Standby mimarisi birkaç temel bileşenden oluşur:

  • Primary Site: Canlı trafiği karşılayan üretim ortamı
  • Standby Site: Azaltılmış kapasitede çalışan, verinin replike edildiği yedek ortam
  • Replikasyon Katmanı: Veritabanı, dosya sistemi ve uygulama state’inin senkronize tutulduğu mekanizma
  • Monitoring ve Failover Orchestration: Sağlık kontrolü yapan ve failover’ı tetikleyen sistem
  • DNS veya Load Balancer Katmanı: Traffic yönlendirmesini yöneten bileşen

Kapasite planlaması konusunda standby sitenizin %50 ile %70 kapasitede çalışması genellikle yeterlidir. Failover sonrası tam kapasite için auto-scaling devreye alınır.

PostgreSQL Streaming Replication ile Veritabanı Katmanı

Veritabanı replikasyonu Warm Standby’ın kalbidir. PostgreSQL’in built-in streaming replication özelliği bu iş için mükemmeldir.

Primary sunucuda PostgreSQL yapılandırması:

# /etc/postgresql/15/main/postgresql.conf
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1GB
synchronous_commit = local
archive_mode = on
archive_command = 'rsync -az %p standby-server:/var/lib/postgresql/wal_archive/%f'
hot_standby = on

Replikasyon kullanıcısı oluşturma ve pg_hba.conf yapılandırması:

# Primary sunucuda
sudo -u postgres psql -c "CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'guclu_sifre_buraya';"

# /etc/postgresql/15/main/pg_hba.conf dosyasına ekle
echo "host replication replicator standby-ip/32 md5" >> /etc/postgresql/15/main/pg_hba.conf

# PostgreSQL'i yeniden yükle
sudo systemctl reload postgresql

Standby sunucuda base backup alıp replikasyonu başlatma:

# Standby sunucuda
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/15/main/*

# Primary'dan base backup al
sudo -u postgres pg_basebackup 
  -h primary-server-ip 
  -U replicator 
  -D /var/lib/postgresql/15/main 
  -P 
  -Xs 
  -R

# pg_basebackup -R flagı ile standby.signal ve recovery ayarları otomatik oluşturulur
# Oluşturulan postgresql.auto.conf'u doğrula
cat /var/lib/postgresql/15/main/postgresql.auto.conf

# Standby'ı başlat
sudo systemctl start postgresql

# Replikasyon durumunu kontrol et (primary'da)
sudo -u postgres psql -c "SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn FROM pg_stat_replication;"

Uygulama Katmanı Senkronizasyonu

Veritabanı hazır, şimdi uygulama sunucularındaki dosya ve konfigürasyonların standby’a taşınması gerekiyor. Bunun için rsync tabanlı sürekli senkronizasyon kullanacağız.

#!/bin/bash
# /usr/local/bin/app_sync.sh
# Uygulama dosyalarını standby'a senkronize eden script

STANDBY_HOST="standby-server.internal"
APP_DIR="/var/www/myapp"
CONFIG_DIR="/etc/myapp"
LOG_FILE="/var/log/app_sync.log"
RSYNC_OPTS="-avz --delete --exclude='*.tmp' --exclude='cache/' --exclude='sessions/'"

timestamp() {
    date '+%Y-%m-%d %H:%M:%S'
}

log() {
    echo "[$(timestamp)] $1" | tee -a "$LOG_FILE"
}

sync_directory() {
    local src=$1
    local dest=$2
    rsync $RSYNC_OPTS "$src" "${STANDBY_HOST}:${dest}" 2>&1
    if [ $? -eq 0 ]; then
        log "SUCCESS: $src senkronize edildi"
    else
        log "ERROR: $src senkronizasyonu basarisiz"
        # Alert gonder
        echo "App sync failed for $src" | mail -s "SYNC ALERT" [email protected]
    fi
}

# Ana senkronizasyon
sync_directory "$APP_DIR/" "$APP_DIR"
sync_directory "$CONFIG_DIR/" "$CONFIG_DIR"

# Sertifikaları da senkronize et
sync_directory "/etc/ssl/myapp/" "/etc/ssl/myapp"

log "Senkronizasyon tamamlandi"

Bu scripti cron ile 5 dakikada bir çalıştırın:

# crontab -e
*/5 * * * * /usr/local/bin/app_sync.sh >> /var/log/app_sync.log 2>&1

Sağlık Kontrolü ve Otomatik Failover

Warm Standby’ın en kritik parçası otomatik failover mekanizmasıdır. Bunu Bash ile basit ama güvenilir bir şekilde implemente edebilirsiniz. Daha karmaşık ortamlar için Patroni veya Pacemaker kullanabilirsiniz ama küçük ve orta ölçekli yapılar için aşağıdaki script gayet işe yarar.

#!/bin/bash
# /usr/local/bin/failover_monitor.sh
# Primary sağlık kontrolü ve otomatik failover

PRIMARY_IP="10.0.1.10"
STANDBY_IP="10.0.1.20"
DNS_ZONE="sirket.internal"
APP_FQDN="app.sirket.internal"
CHECK_INTERVAL=30
FAILURE_THRESHOLD=3
FAILURE_COUNT=0
STATE_FILE="/var/run/failover_state"
LOG_FILE="/var/log/failover_monitor.log"

# Nsupdate için TSIG key
TSIG_KEY="/etc/bind/failover.key"

timestamp() { date '+%Y-%m-%d %H:%M:%S'; }
log() { echo "[$(timestamp)] $1" >> "$LOG_FILE"; echo "[$(timestamp)] $1"; }

check_primary_health() {
    # HTTP health check
    HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" 
        --connect-timeout 5 --max-time 10 
        "http://${PRIMARY_IP}/health")
    
    # PostgreSQL check
    PG_STATUS=$(PGPASSWORD='monitor_pass' psql -h "$PRIMARY_IP" 
        -U monitor -d myapp -c "SELECT 1" -t -q 2>/dev/null | tr -d ' ')
    
    if [ "$HTTP_STATUS" = "200" ] && [ "$PG_STATUS" = "1" ]; then
        return 0
    fi
    return 1
}

perform_failover() {
    log "FAILOVER BASLATIYOR: Primary ${PRIMARY_IP} erisilemez durumda"
    
    # Slack/PagerDuty notification
    curl -s -X POST -H 'Content-type: application/json' 
        --data "{"text":"KRITIK: Failover baslatildi! Standby ${STANDBY_IP} devreye aliyor"}" 
        "$SLACK_WEBHOOK_URL"
    
    # PostgreSQL standby'ı promote et
    ssh -i /root/.ssh/failover_key postgres@"$STANDBY_IP" 
        "pg_ctl promote -D /var/lib/postgresql/15/main"
    
    sleep 5
    
    # DNS kaydını güncelle (bind9 ile)
    nsupdate -k "$TSIG_KEY" << EOF
server dns-server.internal
zone ${DNS_ZONE}
update delete ${APP_FQDN} A
update add ${APP_FQDN} 60 A ${STANDBY_IP}
send
EOF
    
    # Standby'daki nginx'i aktive et
    ssh -i /root/.ssh/failover_key root@"$STANDBY_IP" 
        "systemctl start nginx && systemctl start php-fpm"
    
    echo "failed" > "$STATE_FILE"
    log "FAILOVER TAMAMLANDI: Traffic ${STANDBY_IP} uzerine yonlendirildi"
    
    # Ops ekibine detaylı mail
    mail -s "FAILOVER TAMAMLANDI - Manuel Mudahale Gerekli" [email protected] << MAIL
Failover $(timestamp) zamaninda tamamlandi.
Primary: ${PRIMARY_IP} - ERISILEEMEZ
Standby: ${STANDBY_IP} - AKTIF

Yapilmasi gerekenler:
1. Primary sunucu durumunu kontrol et
2. Primary'i onardiktan sonra failback prosedurunu uygula
3. Replikasyonu yeniden kur
MAIL
}

# Ana dongu
while true; do
    CURRENT_STATE=$(cat "$STATE_FILE" 2>/dev/null || echo "normal")
    
    if [ "$CURRENT_STATE" = "normal" ]; then
        if check_primary_health; then
            FAILURE_COUNT=0
            log "Primary saglikli - Kontrol: OK"
        else
            FAILURE_COUNT=$((FAILURE_COUNT + 1))
            log "Primary saglik kontrolu basarisiz ($FAILURE_COUNT/$FAILURE_THRESHOLD)"
            
            if [ "$FAILURE_COUNT" -ge "$FAILURE_THRESHOLD" ]; then
                perform_failover
            fi
        fi
    fi
    
    sleep "$CHECK_INTERVAL"
done

Failback Prosedürü

Felaket kurtarma planının en çok ihmal edilen kısmı failback, yani standby’dan tekrar primary’a dönüş sürecidir. Bu prosedür dokümante edilmeli ve test edilmelidir.

#!/bin/bash
# /usr/local/bin/failback.sh
# Standby'dan Primary'a geri donuş prosedürü

PRIMARY_IP="10.0.1.10"
STANDBY_IP="10.0.1.20"
DNS_ZONE="sirket.internal"
APP_FQDN="app.sirket.internal"

echo "=== FAILBACK PROSEDURU BASLIYOR ==="
echo "Bu islem once primary'i standby olarak konfigüre edecek"
echo "Sonra rolleri degistirerek eski haline getirecek"
echo ""
read -p "Devam etmek istiyor musunuz? (evet/hayir): " CONFIRM

if [ "$CONFIRM" != "evet" ]; then
    echo "Failback iptal edildi"
    exit 1
fi

echo "[1/5] Primary sunucu saglik kontrolü..."
if ! ping -c 3 "$PRIMARY_IP" > /dev/null 2>&1; then
    echo "ERROR: Primary sunucu hala erisilemez! Failback iptal edildi."
    exit 1
fi

echo "[2/5] Primary'da PostgreSQL'i standby olarak yapilandirma..."
ssh root@"$PRIMARY_IP" << 'REMOTE'
    # Mevcut veriyi temizle ve standby olarak yeniden baslat
    systemctl stop postgresql
    sudo -u postgres rm -rf /var/lib/postgresql/15/main/*
    sudo -u postgres pg_basebackup 
        -h STANDBY_IP_BURAYA 
        -U replicator 
        -D /var/lib/postgresql/15/main 
        -P -Xs -R
    systemctl start postgresql
REMOTE

echo "[3/5] Replikasyon kontrol ediliyor (30 saniye bekleniyor)..."
sleep 30

# Replikasyon lag kontrolü
LAG=$(PGPASSWORD='monitor_pass' psql -h "$STANDBY_IP" -U monitor -d myapp 
    -t -c "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int;" 2>/dev/null | tr -d ' ')

echo "Replikasyon lag: ${LAG} saniye"
if [ "$LAG" -gt 60 ]; then
    echo "UYARI: Replikasyon lag 60 saniyeden fazla. Devam etmek istiyor musunuz?"
    read -p "(evet/hayir): " LAG_CONFIRM
    if [ "$LAG_CONFIRM" != "evet" ]; then exit 1; fi
fi

echo "[4/5] Standby'ı durdurma ve Primary'i promote etme..."
# Standby'daki uygulama trafiğini durdur
ssh root@"$STANDBY_IP" "systemctl stop nginx"

# Primary'i promote et
ssh root@"$PRIMARY_IP" "sudo -u postgres pg_ctl promote -D /var/lib/postgresql/15/main"
sleep 5

echo "[5/5] DNS kaydini guncelleniyor..."
nsupdate -k /etc/bind/failover.key << EOF
server dns-server.internal
zone ${DNS_ZONE}
update delete ${APP_FQDN} A
update add ${APP_FQDN} 300 A ${PRIMARY_IP}
send
EOF

# Standby'ın eski rolüne döndürülmesi
ssh root@"$STANDBY_IP" "systemctl stop postgresql"

echo "=== FAILBACK TAMAMLANDI ==="
echo "Primary ${PRIMARY_IP} artik aktif"
echo "Standby replikasyonu yeniden kurmayi unutmayin!"
echo "State dosyasini temizleyin: rm /var/run/failover_state"

Felaket Kurtarma Testleri

Felaket kurtarma planı test edilmiyorsa yoktur. Warm Standby’ı üç farklı düzeyde test etmenizi öneririm.

Tier 1: Haftalık Otomatik Bileşen Testleri

Bu testler production’ı etkilemez, sadece bileşenlerin sağlıklı olduğunu doğrular:

#!/bin/bash
# /usr/local/bin/dr_health_check.sh
# Her Pazartesi 02:00'de cron ile çalışır

REPORT_FILE="/var/log/dr_weekly_report_$(date +%Y%m%d).txt"
ERRORS=0

check_replication_lag() {
    LAG=$(sudo -u postgres psql -t -c 
        "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int;" 
        2>/dev/null | tr -d ' ')
    
    if [ -z "$LAG" ] || [ "$LAG" -gt 300 ]; then
        echo "FAIL: Replikasyon lag $LAG saniye - kritik esigi asiyor" >> "$REPORT_FILE"
        ERRORS=$((ERRORS + 1))
    else
        echo "OK: Replikasyon lag $LAG saniye" >> "$REPORT_FILE"
    fi
}

check_standby_disk_space() {
    DISK_USAGE=$(ssh root@standby-server "df /var/lib/postgresql | awk 'NR==2{print $5}' | tr -d '%'")
    if [ "$DISK_USAGE" -gt 80 ]; then
        echo "WARN: Standby disk kullanimi %$DISK_USAGE" >> "$REPORT_FILE"
        ERRORS=$((ERRORS + 1))
    else
        echo "OK: Standby disk kullanimi %$DISK_USAGE" >> "$REPORT_FILE"
    fi
}

check_rsync_freshness() {
    # Son sync zamanını kontrol et
    LAST_SYNC=$(ssh root@standby-server "stat -c %Y /var/www/myapp/version.txt 2>/dev/null")
    NOW=$(date +%s)
    DIFF=$((NOW - LAST_SYNC))
    
    if [ "$DIFF" -gt 600 ]; then
        echo "FAIL: Son dosya senkronizasyonu $DIFF saniye once" >> "$REPORT_FILE"
        ERRORS=$((ERRORS + 1))
    else
        echo "OK: Son dosya senkronizasyonu $DIFF saniye once" >> "$REPORT_FILE"
    fi
}

echo "DR Haftalik Saglik Raporu - $(date)" > "$REPORT_FILE"
echo "==========================================" >> "$REPORT_FILE"

check_replication_lag
check_standby_disk_space
check_rsync_freshness

echo "" >> "$REPORT_FILE"
echo "Toplam hata: $ERRORS" >> "$REPORT_FILE"

# Raporu mail ile gonder
mail -s "DR Haftalik Rapor - Hata: $ERRORS" [email protected] < "$REPORT_FILE"

exit $ERRORS

Tier 2: Aylık Tam Failover Testi

Aylık olarak maintenance window açıp gerçek failover testi yapın. Bu test production ortamında değil, traffic’in az olduğu gece saatlerinde yapılabilir veya staging ortamında simüle edilebilir.

Test adımları şunlardır:

  • Primary sunucuyu bilinçli olarak durdur (ağ bağlantısını kes veya servisi durdur)
  • Failover monitor’ün tetiklendiğini izle ve süreyi kaydet
  • Standby’ın trafiği devraldığını fonksiyonel testlerle doğrula
  • RTO ve RPO hedeflerine ulaşılıp ulaşılmadığını kayıt altına al
  • Failback prosedürünü uygula ve sonuçları dokümante et

Her testin ardından şu bilgileri kaydedin:

  • Failover için geçen süre (saniye cinsinden)
  • Veri kaybı miktarı (son commit ile failover anı arasındaki fark)
  • Hangi alarm mekanizmaları tetiklendi
  • Manuel müdahale gerektiren adımlar
  • Sonraki testte iyileştirilecek noktalar

Monitoring ve Alerting Entegrasyonu

Warm Standby’ın işlevsel olması için sürekli gözlemlenmesi gerekir. Prometheus ve Alertmanager ile entegrasyon için temel metrikler şunlardır:

  • pg_stat_replication: Replikasyon lag ve state
  • node_disk_io_time_seconds_total: I/O baskısı
  • node_filesystem_avail_bytes: Disk kapasitesi
  • custom metric: Rsync başarı/başarısızlık oranı

Grafana dashboard’unuzda mutlaka şu paneller olsun:

  • Replikasyon lag (zaman serisi grafik, 5 dakikalık pencere)
  • Son başarılı rsync zamanı
  • Standby servis durumları (PostgreSQL, Nginx, uygulama)
  • Failover geçmişi ve süresi

Gerçek Dünya: Kaçınılması Gereken Hatalar

Yıllar içinde gördüğüm en yaygın Warm Standby hatalarını paylaşayım:

Split-brain durumu: Her iki node da kendini primary sanabilir. Bunu önlemek için STONITH (Shoot The Other Node In The Head) mekanizması veya basitçe DNS-only failover kullanın. Primary’i durdurduğunuzdan emin olmadan standby’ı promote etmeyin.

Test edilmemiş failover: Bir müşterimde gerçek felaket anında failover scripti çalıştı ama PostgreSQL promote komutu beklenmedik bir hata verdi. Nedeni: pg_ctl binary’nin path’i farklıydı ve hiç test edilmemişti. Test etmeden güvenme.

DNS TTL gözardı etme: Failover için DNS güncellerken eski TTL değerleri cachede kalabilir. Kritik kayıtlar için TTL’i normalden 300 saniyede tutun. Felaket öncesinde bunu 60’a düşürmek iyi bir pratiktir.

Replikasyon lag alarmını görmezden gelme: “Biraz lag var, düzelir” demek felaket habercisidir. Replikasyon lag 5 dakikayı geçtiğinde mutlaka araştırın.

Sadece veritabanını düşünmek: Uygulama session’ları, Redis cache, job queue’lar, cronjob state’leri de replikasyona dahil edilmelidir. Sadece PostgreSQL’i kopyalamak yeterli değildir.

Sonuç

Warm Standby mimarisi, gerçek dünyada dengeyi doğru kuran bir felaket kurtarma yaklaşımıdır. Hot Standby kadar pahalı değil ama Cold Standby kadar riskli de değil. Kritik nokta şu: mimariyi kurmak başlangıçtır, düzenli test etmek onu hayata geçirir.

Bu yazıda anlattığım yapıyı kendi ortamınıza adapte ederken şu öncelikleri gözetin: Önce veritabanı replikasyonunu sağlam kurun ve lag’ı sürekli izleyin. Sonra dosya senkronizasyonunu otomatize edin. Ardından failover/failback scriptlerini yazın ve her ikisini de test edin. Son olarak tüm bu süreçleri monitoring’e bağlayın ve aylık testleri takvime koyun.

Ekibinizde herkes DR prosedürünü bilmeli. Felaket gece 02:00’de gerçekleşir ve o saatte en deneyimli ekip üyeniz ulaşılamaz olabilir. Runbook’larınızı güncel tutun, onboarding sürecinize DR testini dahil edin ve her başarılı failover testini bir kutlama olarak değil, sistemin çalıştığının kanıtı olarak kaydedin.

Bir yanıt yazın

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