Yedek Rotasyonu ve Disk Yönetimi: rsync ile Akıllı Yedekleme
Yedekleme yapmak bir erdem, ama yedekleri doğru yönetmemek felaketi geciktirmekten ibaretten başka bir şey değildir. Disk dolunca ne olur? Eski yedekler nereye gider? 30 günlük yedek tutmak istiyorsun ama diskin 3 günde bir doluyorsa ne yapacaksın? Bu sorular sysadmin hayatının tam ortasında durur ve cevapları rsync ile otomatik yedek rotasyonu kavramında gizlidir.
Yedek Rotasyonu Nedir ve Neden Önemlidir?
Yedek rotasyonu, belirli bir politikaya göre eski yedekleri silip yenilerini tutma sürecidir. Basit görünür ama yanlış yapılırsa ya disk dolar ya da kritik bir yedek dosyayı kaybedersin.
Gerçek dünya senaryosunu düşün: Bir e-ticaret şirketinde sistem yöneticisisin. Her gece 50 GB’lık bir yedek alıyorsun. 30 gün sonra diskin dolduğunu ve yedekleme scriptinin sessizce hata verdiğini fark ediyorsun. 31. günde kritik bir veri kaybı yaşandığında elimde yedek sandın ama aslında son 5 gündür yedek alınmıyordu. Bu senaryo maalesef kurgu değil.
Etkili bir rotasyon stratejisi şunları sağlar:
- Disk kullanımını kontrol altında tutar: Belirli bir limit içinde kalırsın
- Farklı zaman noktalarına erişim: Dün, geçen hafta, geçen ay gibi
- Otomatik temizlik: Manuel müdahale gerekmez
- Öngörülebilir alan kullanımı: Kapasite planlaması yapabilirsin
Rsync’i Yedek Rotasyonu İçin Doğru Kullanmak
Rsync kendi başına bir rotasyon aracı değildir. Ancak --backup, --backup-dir ve --link-dest gibi parametreleriyle bu işi son derece verimli yapabilirsin.
Temel Rsync Parametrelerini Hatırlayalım
Rotasyon konusuna geçmeden önce kullanacağımız parametreleri netleştirelim:
- –link-dest=DIR: Değişmeyen dosyalar için hard link oluşturur, disk alanı tasarrufu sağlar
- –backup: Üzerine yazılacak dosyaları yedekler
- –backup-dir=DIR: Yedeklenen dosyaların konumunu belirtir
- –delete: Kaynak dizinde olmayan dosyaları hedeften siler
- –archive (-a): Recursive, symlink, permission, timestamp koruması sağlar
- –exclude=PATTERN: Belirtilen pattern’ı yedekleme dışında bırakır
- –log-file=FILE: İşlemleri log dosyasına yazar
Hard Link Tabanlı Artımlı Yedekleme
Bu yöntem, rsync ile yedek rotasyonunun kalbidir. Her gün tam bir yedek almış gibi görünürken aslında sadece değişen dosyaları depolarsın.
#!/bin/bash
# hard_link_backup.sh - Temel hard link yedekleme scripti
SOURCE="/var/www/html"
DEST="/backup/webserver"
DATE=$(date +%Y-%m-%d)
LATEST="$DEST/latest"
# Yedek dizini oluştur
mkdir -p "$DEST/$DATE"
# Hard link tabanlı artımlı yedek al
rsync -av
--link-dest="$LATEST"
--exclude="*.tmp"
--exclude="*.log"
--delete
"$SOURCE/"
"$DEST/$DATE/"
# latest symlink'ini güncelle
rm -f "$LATEST"
ln -s "$DEST/$DATE" "$LATEST"
echo "Yedek tamamlandi: $DEST/$DATE"
Bu scripti çalıştırdığında, $DEST/ içinde her gün için ayrı bir klasör oluşur. Değişmeyen dosyalar hard link ile bağlandığı için disk kullanımı minimum seviyede kalır. 1 GB’lık bir dizini 30 gün yedeklersen ve her gün 10 MB değişiklik olursa, teorik olarak 30 GB değil yaklaşık 1.3 GB disk kullanırsın.
Rotasyon Stratejileri
Günlük-Haftalık-Aylık Rotasyon (GFS – Grandfather-Father-Son)
Bu klasik yaklaşım, farklı granülaritede yedek tutmanı sağlar. Son 7 günü günlük, son 4 haftayı haftalık, son 12 ayı aylık tutarsın.
#!/bin/bash
# gfs_rotation.sh - Grandfather-Father-Son rotasyon scripti
SOURCE="/home"
BACKUP_ROOT="/backup/gfs"
DATE=$(date +%Y-%m-%d)
DAY_OF_WEEK=$(date +%u) # 1=Pazartesi, 7=Pazar
DAY_OF_MONTH=$(date +%d) # 01-31
DAILY_DIR="$BACKUP_ROOT/daily"
WEEKLY_DIR="$BACKUP_ROOT/weekly"
MONTHLY_DIR="$BACKUP_ROOT/monthly"
mkdir -p "$DAILY_DIR" "$WEEKLY_DIR" "$MONTHLY_DIR"
# Önce günlük yedeği al
rsync -a
--link-dest="$DAILY_DIR/latest"
--delete
--log-file="/var/log/backup_daily.log"
"$SOURCE/"
"$DAILY_DIR/$DATE/"
rm -f "$DAILY_DIR/latest"
ln -s "$DAILY_DIR/$DATE" "$DAILY_DIR/latest"
# Pazar günü haftalık yedeği kopyala (hard link ile)
if [ "$DAY_OF_WEEK" -eq 7 ]; then
WEEK=$(date +%Y-W%V)
cp -al "$DAILY_DIR/$DATE" "$WEEKLY_DIR/$WEEK"
echo "Haftalik yedek olusturuldu: $WEEKLY_DIR/$WEEK"
fi
# Ayın ilk günü aylık yedeği kopyala
if [ "$DAY_OF_MONTH" -eq "01" ]; then
MONTH=$(date +%Y-%m)
cp -al "$DAILY_DIR/$DATE" "$MONTHLY_DIR/$MONTH"
echo "Aylik yedek olusturuldu: $MONTHLY_DIR/$MONTH"
fi
# Eski yedekleri temizle
# Son 7 günlük yedekleri tut
find "$DAILY_DIR" -maxdepth 1 -type d -name "????-??-??" |
sort -r | tail -n +8 | xargs rm -rf
# Son 4 haftalık yedekleri tut
find "$WEEKLY_DIR" -maxdepth 1 -type d |
sort -r | tail -n +5 | xargs rm -rf
# Son 12 aylık yedekleri tut
find "$MONTHLY_DIR" -maxdepth 1 -type d |
sort -r | tail -n +13 | xargs rm -rf
echo "GFS rotasyonu tamamlandi: $(date)"
Basit N-Günlük Rotasyon
Daha basit bir ihtiyaç için, sadece son N günü tutmak isteyebilirsin:
#!/bin/bash
# simple_rotation.sh - Son N gün yedek tut
SOURCE="/etc"
DEST="/backup/etc_backup"
KEEP_DAYS=14
DATE=$(date +%Y-%m-%d_%H-%M)
mkdir -p "$DEST/$DATE"
rsync -av
--link-dest="$DEST/current"
"$SOURCE/"
"$DEST/$DATE/"
# current symlink güncelle
rm -f "$DEST/current"
ln -s "$DEST/$DATE" "$DEST/current"
# KEEP_DAYS'den eski dizinleri sil
find "$DEST"
-maxdepth 1
-type d
-name "????-??-??_??-??"
-mtime +$KEEP_DAYS
-exec rm -rf {} ;
# Disk kullanimi raporu
echo "--- Yedek Disk Kullanimi ---"
du -sh "$DEST"/*
echo "Toplam: $(du -sh $DEST | cut -f1)"
Disk Yönetimi ve İzleme
Rotasyonun işe yaraması için disk durumunu sürekli izlemen gerekir. Disk dolduğunda en kötü an yedekleme sırasında gelir.
Disk Durumu Kontrol Scripti
#!/bin/bash
# disk_monitor.sh - Yedek diski izle ve uyar
BACKUP_MOUNT="/backup"
WARN_THRESHOLD=80 # %80 dolulukta uyar
CRITICAL_THRESHOLD=90 # %90 dolulukta kritik uyar
ALERT_EMAIL="[email protected]"
LOG="/var/log/backup_disk_monitor.log"
# Disk kullanim yuzdesini al
USAGE=$(df "$BACKUP_MOUNT" | awk 'NR==2 {print $5}' | tr -d '%')
AVAIL=$(df -h "$BACKUP_MOUNT" | awk 'NR==2 {print $4}')
TOTAL=$(df -h "$BACKUP_MOUNT" | awk 'NR==2 {print $2}')
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] Disk kullanimi: %$USAGE (Bos: $AVAIL / Toplam: $TOTAL)" >> "$LOG"
if [ "$USAGE" -ge "$CRITICAL_THRESHOLD" ]; then
MSG="KRITIK: Yedek diski %$USAGE dolu! Bos alan: $AVAIL"
echo "$MSG" | mail -s "KRITIK - Yedek Diski Dolmak Uzere" "$ALERT_EMAIL"
echo "[$TIMESTAMP] KRITIK UYARI gonderildi" >> "$LOG"
elif [ "$USAGE" -ge "$WARN_THRESHOLD" ]; then
MSG="UYARI: Yedek diski %$USAGE dolu. Bos alan: $AVAIL"
echo "$MSG" | mail -s "UYARI - Yedek Diski Izle" "$ALERT_EMAIL"
echo "[$TIMESTAMP] Uyari gonderildi" >> "$LOG"
fi
Yedek Boyutlarını Raporlama
Rotasyon çalışıyor mu, boyutlar beklenen aralıkta mı? Bunu düzenli raporlarla takip etmelisin:
#!/bin/bash
# backup_report.sh - Gunluk yedek raporu
BACKUP_ROOT="/backup"
REPORT_FILE="/var/log/backup_report_$(date +%Y-%m-%d).txt"
echo "========================================" > "$REPORT_FILE"
echo "Yedek Raporu: $(date '+%Y-%m-%d %H:%M')" >> "$REPORT_FILE"
echo "========================================" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "--- Disk Genel Durum ---" >> "$REPORT_FILE"
df -h "$BACKUP_ROOT" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "--- Yedek Dizin Boyutlari ---" >> "$REPORT_FILE"
du -sh "$BACKUP_ROOT"/*/ 2>/dev/null | sort -h >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "--- Son 7 Gun Yedek Boyutlari ---" >> "$REPORT_FILE"
find "$BACKUP_ROOT"
-maxdepth 2
-type d
-name "????-??-??*"
-newer "$BACKUP_ROOT/$(date -d '7 days ago' +%Y-%m-%d)"
-exec du -sh {} ; 2>/dev/null | sort >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "--- Inode Kullanimi ---" >> "$REPORT_FILE"
df -i "$BACKUP_ROOT" >> "$REPORT_FILE"
# Raporu mail ile gonder (opsiyonel)
cat "$REPORT_FILE" | mail -s "Gunluk Yedek Raporu" [email protected]
echo "Rapor olusturuldu: $REPORT_FILE"
İnode Tükenmesi Sorunu
Hard link tabanlı yedeklemede sık karşılaşılan ama çoğu zaman göz ardı edilen bir sorun: inode tükenmesi. Disk dolmamış olabilir ama inode limiti aşılırsa yeni dosya oluşturulamaz.
Bu durumu izlemek için:
# Inode kullanimi kontrol
df -i /backup
# Bir dizindeki toplam dosya ve hard link sayisi
find /backup -type f | wc -l
find /backup -links +1 -type f | wc -l
# En cok inode kullanan alt dizinler
for dir in /backup/*/; do
echo -n "$dir: "
find "$dir" -type f | wc -l
done | sort -t: -k2 -n -r | head -10
Eğer ext4 dosya sistemi kullanıyorsan ve inode tükenmesi sık yaşıyorsan, yeni bir dosya sistemi oluşturken -i parametresiyle inode yoğunluğunu artırabilirsin:
# Daha fazla inode ile ext4 formatla (bytes-per-inode kucultuldu)
mkfs.ext4 -i 4096 /dev/sdb1
Gerçek Dünya Senaryosu: Web Sunucusu Yedek Rotasyonu
Üretim ortamında çalışan bir yapılandırma örneği verelim. 3 web sunucusu var, her birinin /var/www ve /etc/nginx dizinleri merkezi bir yedek sunucusuna rsync ile kopyalanıyor.
#!/bin/bash
# production_backup.sh - Merkezi yedek scripti
# /etc/cron.d/backup-rotation dosyasina ekle:
# 0 2 * * * root /opt/scripts/production_backup.sh
set -euo pipefail
# Konfigürasyon
BACKUP_ROOT="/mnt/backup-nas"
LOG_DIR="/var/log/backups"
KEEP_DAILY=7
KEEP_WEEKLY=4
SSH_KEY="/root/.ssh/backup_key"
TIMESTAMP=$(date +%Y-%m-%d)
WEEKDAY=$(date +%u)
# Sunucu listesi
SERVERS=("web01.internal" "web02.internal" "web03.internal")
# Yedeklenecek dizinler
PATHS=("/var/www" "/etc/nginx" "/etc/ssl")
mkdir -p "$LOG_DIR"
backup_server() {
local SERVER=$1
local LOGFILE="$LOG_DIR/${SERVER}_${TIMESTAMP}.log"
echo "=== $SERVER yedeği başlıyor: $(date) ===" | tee -a "$LOGFILE"
for PATH_TO_BACKUP in "${PATHS[@]}"; do
# Dizin adini al (/ karakterlerini _ ile degistir)
DIR_NAME=$(echo "$PATH_TO_BACKUP" | tr '/' '_' | sed 's/^_//')
DEST="$BACKUP_ROOT/$SERVER/$DIR_NAME"
LATEST="$DEST/latest"
mkdir -p "$DEST/$TIMESTAMP"
# Hard link tabanli rsync
if [ -L "$LATEST" ]; then
rsync -az
--link-dest="$LATEST"
--delete
--exclude="*.cache"
--exclude="*.sess_*"
--log-file="$LOGFILE"
-e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no"
"backup@${SERVER}:${PATH_TO_BACKUP}/"
"$DEST/$TIMESTAMP/"
else
# Ilk kez yedekleme - link-dest yok
rsync -az
--delete
--log-file="$LOGFILE"
-e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no"
"backup@${SERVER}:${PATH_TO_BACKUP}/"
"$DEST/$TIMESTAMP/"
fi
# Symlink güncelle
rm -f "$LATEST"
ln -s "$DEST/$TIMESTAMP" "$LATEST"
echo "$PATH_TO_BACKUP yedeği tamamlandı" | tee -a "$LOGFILE"
done
# Eski yedekleri temizle
find "$BACKUP_ROOT/$SERVER"
-maxdepth 2
-type d
-name "????-??-??"
| sort -r
| tail -n +$((KEEP_DAILY + 1))
| xargs -r rm -rf
echo "=== $SERVER yedeği tamamlandı: $(date) ===" | tee -a "$LOGFILE"
}
# Tüm sunucuları paralel yedekle
for SERVER in "${SERVERS[@]}"; do
backup_server "$SERVER" &
done
# Tum arka plan islemleri bitene kadar bekle
wait
echo "Tum sunucu yedekleri tamamlandi: $(date)"
# Genel disk kullanim raporu
df -h "$BACKUP_ROOT"
du -sh "$BACKUP_ROOT"/*/
Cron ile Otomatik Zamanlama
Rotasyon scriptlerini cron ile zamanlarken dikkat etmen gereken bazı noktalar var:
# /etc/cron.d/backup-rotation
# Ortam değişkenleri
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
[email protected]
# Her gece 02:00'de günlük yedek ve rotasyon
0 2 * * * root /opt/scripts/gfs_rotation.sh >> /var/log/backup_cron.log 2>&1
# Her saat disk izleme
0 * * * * root /opt/scripts/disk_monitor.sh
# Her sabah 07:00'de rapor
0 7 * * * root /opt/scripts/backup_report.sh
Cron çıktısını doğrudan log dosyasına yönlendirmen önemlidir çünkü MAILTO ayarlı olsa bile uzun çıktılar bazen mail ile kaybolur.
Sık Yapılan Hatalar ve Çözümleri
Yedek rotasyonunda yıllar içinde öğrenilen derslerin bir özeti:
- Rotasyon scriptini test etmemek:
--dry-runile önce simüle et, gerçek ortamda çalıştırmadan önce test sunucusunda dene - Yedek başarısını doğrulamamak: Script çıkış kodunu kontrol et,
set -ekullan ve yedek sonrasırsync --checksumile doğrulama yap - Sadece disk doluluk izlemek: Inode kullanımını da izle, büyük dosya sayısı olan ortamlarda kritik önem taşır
- Symlink’lere güvenmek:
latestsymlink’i bozulabilir, bunu kontrol eden bir mekanizma ekle - Paralel yedeklerin disk I/O yarışması: Birden fazla sunucuyu aynı anda yedekliyorsan
ioniceile I/O önceliğini ayarla
# Dusuk I/O onceligi ile rsync calistir
ionice -c 3 rsync -av /source /dest
# Bant genisligi sinirla (1MB/s)
rsync -av --bwlimit=1024 /source /dest
Yedek Bütünlüğü Doğrulaması
Rotasyon sistemi kurulunca iş bitmez. Yedeklerin gerçekten geri yüklenebilir olduğunu düzenli test etmelisin:
#!/bin/bash
# verify_backup.sh - Rastgele dosya dogrulama
BACKUP_LATEST="/backup/webserver/latest"
SOURCE="/var/www/html"
SAMPLE_SIZE=10
ERRORS=0
echo "Yedek dogrulama basliyor: $(date)"
# Kaynak dizinden rastgele dosya sec
FILES=$(find "$SOURCE" -type f | shuf | head -$SAMPLE_SIZE)
while IFS= read -r SOURCE_FILE; do
# Yedek tarafindaki karsilik gelen dosyayi bul
REL_PATH="${SOURCE_FILE#$SOURCE/}"
BACKUP_FILE="$BACKUP_LATEST/$REL_PATH"
if [ ! -f "$BACKUP_FILE" ]; then
echo "HATA: Yedekte bulunamadi: $REL_PATH"
((ERRORS++))
continue
fi
# MD5 karsilastir
SOURCE_MD5=$(md5sum "$SOURCE_FILE" | cut -d' ' -f1)
BACKUP_MD5=$(md5sum "$BACKUP_FILE" | cut -d' ' -f1)
if [ "$SOURCE_MD5" != "$BACKUP_MD5" ]; then
echo "HATA: MD5 eslesmiyor: $REL_PATH"
((ERRORS++))
else
echo "OK: $REL_PATH"
fi
done <<< "$FILES"
echo "Dogrulama tamamlandi. Hata sayisi: $ERRORS"
exit $ERRORS
Sonuç
Rsync ile yedek rotasyonu, disk yönetiminin en verimli çözümlerinden biri olmaya devam ediyor. Hard link tabanlı artımlı yedekleme sayesinde hem disk alanını koruyorsun hem de her gün için tam bir anlık görüntüye sahip oluyorsun. GFS stratejisiyle birleştiğinde günlük, haftalık ve aylık zaman noktalarına erişim imkânı buluyorsun.
Ancak asıl değer, bu scriptleri yazıp geçmek değil, onları izlemek, test etmek ve geliştirmek üzerine kurulan bir kültür oluşturmaktır. Disk izleme alarmsız bir rotasyon sistemi yarım iştir. Bütünlük doğrulaması olmayan bir yedek sistemi ise seni yanlış bir güvenlik hissine sokar.
Gerçek sysadmin becerisi, felaketi önlemekte değil, felaket geldiğinde hazır olmakta yatar. Ve o hazırlık, her gece sessizce çalışan, raporlarını sabah gönderen, diskini dengede tutan bir rotasyon scriptinden geçer.
