tar ile Uzun Süren Yedeklerde Checkpointing ve İlerleme Günlüğü Tutma

Saatler süren bir yedekleme işlemi, tam 3’te bitecekken network bir anlık kesildi ve tar prosesi öldü. Başa dön, tekrar başlat, tekrar bekle. Bu senaryoyu yaşamamış sysadmin yoktur aramızda. İşte tam bu noktada checkpointing ve ilerleme günlüğü tutma kavramları hayat kurtarıcı oluyor.

Bu yazıda GNU tar’ın az bilinen ama son derece güçlü checkpoint mekanizmasını, ilerleme günlüğü tutmanın pratik yollarını ve uzun süren yedekleme işlemlerinde kurtarma noktası belirleyerek işlemi kaldığı yerden devam ettirme tekniklerini ele alacağız. Teorik değil, gerçekten işe yarayan yöntemler bunlar.

tar’ın Checkpoint Mekanizması Nedir?

GNU tar, --checkpoint seçeneğiyle belirli aralıklarla bir “kontrol noktası” üretir. Bu kontrol noktaları aslında tar’ın kaç tane 512 baytlık blok işlediğini saymasına dayanır. Varsayılan olarak her 10 blokta bir checkpoint üretilir, ama bu değeri ihtiyacınıza göre ayarlayabilirsiniz.

Checkpoint mekanizmasının tek başına bir “kaldığı yerden devam et” özelliği sunmadığını baştan söyleyelim. Tar bu anlamda rsync değil. Ancak checkpoint sistemi, ilerleme takibi, dış araçlarla entegrasyon ve özellikle --index-file ile birlikte kullanıldığında gerçek anlamda kurtarılabilir yedekleme altyapısı kurmanızı sağlıyor.

# Temel checkpoint kullanımı - her 1000 blokta bir nokta bas
tar --checkpoint=1000 -czf /backup/sistem.tar.gz /var/www/

# Checkpoint mesajını özelleştir
tar --checkpoint=1000 --checkpoint-action=echo="%u blok islendi, dosya: %s" 
    -czf /backup/sistem.tar.gz /var/www/

Buradaki %u toplam blok sayısını, %s o an işlenen dosyayı gösteriyor. Checkpoint action formatında kullanabileceğiniz değişkenler oldukça zengin.

İlerleme Günlüğü Tutmanın Doğru Yolu

Sadece ekrana yazdırmak yetmez. Uzun süren işlemlerde ilerlemeyi bir dosyaya kaydetmek, hem anlık izleme hem de hata sonrası analiz için kritik.

#!/bin/bash
# backup_with_progress.sh

BACKUP_SRC="/var/www /etc /home"
BACKUP_DEST="/mnt/backup/sistem_$(date +%Y%m%d_%H%M).tar.gz"
LOG_FILE="/var/log/backup/progress_$(date +%Y%m%d_%H%M).log"
INDEX_FILE="/var/log/backup/index_$(date +%Y%m%d_%H%M).txt"

mkdir -p /var/log/backup

echo "Yedekleme basladi: $(date)" | tee -a "$LOG_FILE"

tar 
  --checkpoint=500 
  --checkpoint-action=echo="[%T] Blok %u islendi: %s" 
  --index-file="$INDEX_FILE" 
  -czf "$BACKUP_DEST" 
  $BACKUP_SRC 
  2>&1 | tee -a "$LOG_FILE"

EXIT_CODE=${PIPESTATUS[0]}

if [ $EXIT_CODE -eq 0 ]; then
    echo "Yedekleme basariyla tamamlandi: $(date)" | tee -a "$LOG_FILE"
    echo "Arsiv boyutu: $(du -sh $BACKUP_DEST | cut -f1)" | tee -a "$LOG_FILE"
else
    echo "HATA: Yedekleme basarisiz oldu. Cikis kodu: $EXIT_CODE" | tee -a "$LOG_FILE"
fi

--index-file parametresi burada altın değerinde. Bu parametre, arşive giren her dosyanın hangi blokta başladığını kaydeden bir dizin dosyası oluşturuyor. Yani hem hangi dosyaların yedeklendiğini görüyorsunuz hem de bir şeyler ters giderse hangi noktaya kadar ulaşıldığını anlıyorsunuz.

Checkpoint Action Seçenekleri

GNU tar’ın checkpoint-action parametresi birden fazla eylem destekliyor. Sadece echo değil, dış komutlar da çalıştırabilirsiniz.

# Her checkpoint'te hem ekrana yaz hem bir script calistir
tar 
  --checkpoint=1000 
  --checkpoint-action=echo="Kontrol noktasi: %u" 
  --checkpoint-action=exec=/usr/local/bin/checkpoint_handler.sh 
  -czf /backup/buyuk_arsiv.tar.gz /data/

checkpoint_handler.sh içinde ne yapabilirsiniz? Neredeyse her şey. İlerlemeyi bir veritabanına yazabilir, Slack’e bildirim gönderebilir, disk doluluk oranını kontrol edip gerekirse işlemi durdurabilirsiniz.

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

TAR_CHECKPOINT="${TAR_CHECKPOINT}"
TAR_ARCHIVE="${TAR_ARCHIVE}"

# Disk kontrolu - %90 doluysa dur
DISK_USAGE=$(df /mnt/backup | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 90 ]; then
    echo "KRITIK: Disk dolulugu %$DISK_USAGE. Yedekleme durduruluyor!" 
        >> /var/log/backup/alerts.log
    kill -SIGTERM $PPID
    exit 1
fi

# Her 100 checkpoint'te bir log yaz (10000 blokta bir)
if [ $((TAR_CHECKPOINT % 100)) -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Checkpoint: $TAR_CHECKPOINT, Arsiv: $TAR_ARCHIVE" 
        >> /var/log/backup/milestones.log
fi

Tar, checkpoint action scripti çalıştırırken TAR_CHECKPOINT, TAR_ARCHIVE ve TAR_BLOCKING_FACTOR ortam değişkenlerini otomatik olarak set ediyor. Bu değişkenleri script içinde kullanabilirsiniz.

Büyük Arşivlerde Dosya Listesi ile İlerleme Tahmini

Gerçekten büyük yedeklemeler için (yüz binlerce dosya, terabaytlarca veri) önce dosya listesi oluşturup sonra bu listeyi kullanmak hem daha kontrollü hem de daha takip edilebilir bir yaklaşım sunuyor.

#!/bin/bash
# Once dosya listesi olustur
FILELIST="/tmp/backup_filelist_$(date +%Y%m%d).txt"
BACKUP_DEST="/mnt/backup/arsiv_$(date +%Y%m%d).tar.gz"

find /data -type f -not -name "*.tmp" -not -name "*.cache" > "$FILELIST"

TOTAL_FILES=$(wc -l < "$FILELIST")
echo "Toplam yedeklenecek dosya: $TOTAL_FILES"

# Dosya listesinden yedekle, ilerlemeyi takip et
tar 
  --checkpoint=2000 
  --checkpoint-action=echo="$(date '+%H:%M:%S') - %u. blok - Dosya: %s" 
  --files-from="$FILELIST" 
  --index-file="/var/log/backup/index_$(date +%Y%m%d).txt" 
  -czf "$BACKUP_DEST"

echo "Tamamlandi. Kontrol: $(tar -tzf $BACKUP_DEST | wc -l) dosya arsivlendi."

Bu yaklaşımın bir başka avantajı da var: Filelist dosyasını saklarsanız, bir sonraki çalıştırmada hangi dosyaların zaten yedeklendiğini görmek için index dosyasıyla karşılaştırabilirsiniz.

Kesintiye Uğrayan Yedeklemeleri Kurtarma

İşte en can alıcı kısım. tar’ın native olarak “kaldığı yerden devam et” özelliği yok, ama index dosyasını kullanarak neyin yedeklenip neyin yedeklenmediğini anlayabilir ve eksik dosyaları ayrı bir arşiv olarak alabilirsiniz.

#!/bin/bash
# recover_backup.sh - Yarim kalan yedeklemeyi tamamla

ORIGINAL_FILELIST="/tmp/backup_filelist_20241215.txt"
COMPLETED_INDEX="/var/log/backup/index_20241215.txt"
REMAINING_FILELIST="/tmp/remaining_files_$(date +%Y%m%d_%H%M).txt"
SUPPLEMENTAL_BACKUP="/mnt/backup/arsiv_ek_$(date +%Y%m%d_%H%M).tar.gz"

# Index dosyasindan tamamlanan dosyalari cek
# Index dosyasi formatı: "blok_no dosya_yolu" seklinde
awk '{print $2}' "$COMPLETED_INDEX" | sort > /tmp/completed_files.txt
sort "$ORIGINAL_FILELIST" > /tmp/sorted_original.txt

# Tamamlanmayanları bul
comm -23 /tmp/sorted_original.txt /tmp/completed_files.txt > "$REMAINING_FILELIST"

REMAINING_COUNT=$(wc -l < "$REMAINING_FILELIST")
echo "Tamamlanmamis dosya sayisi: $REMAINING_COUNT"

if [ "$REMAINING_COUNT" -gt 0 ]; then
    echo "Eksik dosyalar yedekleniyor..."
    tar 
      --checkpoint=1000 
      --checkpoint-action=echo="[%T] %u. blok: %s" 
      --files-from="$REMAINING_FILELIST" 
      --index-file="/var/log/backup/index_ek_$(date +%Y%m%d_%H%M).txt" 
      -czf "$SUPPLEMENTAL_BACKUP"
    
    echo "Ek yedekleme tamamlandi: $SUPPLEMENTAL_BACKUP"
else
    echo "Tum dosyalar zaten yedeklenmis."
fi

Bu script’in çalışabilmesi için index dosyasının düzgün oluşturulmuş olması gerekiyor. Yedekleme başlamadan önce --index-file parametresini mutlaka ekleyin, sonradan ekleyemezsiniz.

pv ile Gerçek Zamanlı İlerleme Göstergesi

pv (pipe viewer) kuruluysa, tar ile birlikte kullanmak çok daha görsel bir ilerleme takibi sağlıyor. Özellikle disk üzerinden disk’e kopyalama senaryolarında mükemmel çalışıyor.

# pv ile ilerleme gostergesi
# Once toplam boyutu hesapla
TOTAL_SIZE=$(du -sb /var/www /etc /home 2>/dev/null | awk '{sum+=$1} END {print sum}')

tar -czp 
    --checkpoint=1000 
    --checkpoint-action=echo="Blok: %u" 
    /var/www /etc /home | 
    pv -s "$TOTAL_SIZE" -p -t -e -r | 
    gzip > /mnt/backup/sistem_$(date +%Y%m%d).tar.gz

# Ya da daha basit sekilde boyut tahmini olmadan
tar -cp /data | pv | gzip > /mnt/backup/data_backup.tar.gz

pv’nin parametrelerine bakalım:

  • -s BOYUT: Toplam beklenen boyutu belirler, yüzde hesaplamak için gerekli
  • -p: İlerleme çubuğu göster
  • -t: Geçen süreyi göster
  • -e: Tahmini bitiş süresini göster
  • -r: Anlık transfer hızını göster
  • -b: Toplam işlenen bayt sayısını göster

Paralel Yedekleme ve Bölünmüş Arşivler

Çok büyük veri setlerinde tek bir tar işlemi yerine dizinleri paralel olarak yedeklemek ve her birini ayrı takip etmek daha yönetilebilir.

#!/bin/bash
# parallel_backup.sh - Dizinleri paralel yedekle

BACKUP_DATE=$(date +%Y%m%d_%H%M)
BACKUP_BASE="/mnt/backup/$BACKUP_DATE"
LOG_BASE="/var/log/backup/$BACKUP_DATE"

mkdir -p "$BACKUP_BASE" "$LOG_BASE"

backup_directory() {
    local DIR="$1"
    local NAME=$(echo "$DIR" | tr '/' '_' | sed 's/^_//')
    local DEST="$BACKUP_BASE/${NAME}.tar.gz"
    local LOG="$LOG_BASE/${NAME}.log"
    local INDEX="$LOG_BASE/${NAME}.index"
    
    echo "$(date '+%H:%M:%S') Basladi: $DIR" | tee "$LOG"
    
    tar 
        --checkpoint=500 
        --checkpoint-action=echo="$(date '+%H:%M:%S') [${NAME}] %u. blok: %s" 
        --index-file="$INDEX" 
        -czf "$DEST" 
        "$DIR" 
        2>&1 | tee -a "$LOG"
    
    local EXIT_CODE=${PIPESTATUS[0]}
    
    if [ $EXIT_CODE -eq 0 ]; then
        local SIZE=$(du -sh "$DEST" | cut -f1)
        local COUNT=$(wc -l < "$INDEX")
        echo "$(date '+%H:%M:%S') Tamamlandi: $DIR | Boyut: $SIZE | Dosya: $COUNT" 
            | tee -a "$LOG"
    else
        echo "$(date '+%H:%M:%S') HATA ($EXIT_CODE): $DIR" | tee -a "$LOG"
    fi
}

export -f backup_directory
export BACKUP_BASE LOG_BASE

# Paralel calistir (max 3 es zamanli islem)
DIRS=("/var/www" "/home" "/opt/apps" "/etc" "/var/lib/mysql/backup")
printf '%sn' "${DIRS[@]}" | xargs -P 3 -I{} bash -c 'backup_directory "$@"' _ {}

echo "Tum yedeklemeler tamamlandi: $(date)"
echo "Ozet:"
for dir in "$LOG_BASE"/*.log; do
    tail -1 "$dir"
done

Yedekleme Bütünlüğünü Doğrulama

Yedek almak kadar önemli olan şey, alınan yedeğin sağlam olduğunu doğrulamak. Uzun süren işlemlerde bu adım çok sık atlanıyor.

#!/bin/bash
# verify_backup.sh

BACKUP_FILE="$1"
INDEX_FILE="$2"

if [ -z "$BACKUP_FILE" ]; then
    echo "Kullanim: $0 <arsiv.tar.gz> [index_dosyasi]"
    exit 1
fi

echo "=== Yedekleme Dogrulama Raporu ==="
echo "Arsiv: $BACKUP_FILE"
echo "Tarih: $(date)"
echo ""

# Arsiv butunlugu kontrol
echo "1. Arsiv butunlugu test ediliyor..."
tar -tzf "$BACKUP_FILE" > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "   BASARILI: Arsiv butunlugu tamam"
else
    echo "   HATA: Arsiv bozuk veya tamamlanmamis!"
    exit 1
fi

# Dosya sayisi
FILE_COUNT=$(tar -tzf "$BACKUP_FILE" | grep -v '/$' | wc -l)
echo "2. Arsivdeki dosya sayisi: $FILE_COUNT"

# SHA256 checksum olustur veya dogrula
CHECKSUM_FILE="${BACKUP_FILE}.sha256"
if [ -f "$CHECKSUM_FILE" ]; then
    echo "3. Checksum dogrulanıyor..."
    sha256sum -c "$CHECKSUM_FILE" 2>&1
else
    echo "3. Checksum olusturuluyor..."
    sha256sum "$BACKUP_FILE" > "$CHECKSUM_FILE"
    echo "   Kaydedildi: $CHECKSUM_FILE"
fi

# Index ile karsilastir
if [ -n "$INDEX_FILE" ] && [ -f "$INDEX_FILE" ]; then
    INDEX_COUNT=$(wc -l < "$INDEX_FILE")
    echo "4. Index dosyasi: $INDEX_COUNT kayit"
    
    DIFF=$((FILE_COUNT - INDEX_COUNT))
    if [ "$DIFF" -ne 0 ]; then
        echo "   UYARI: Arsiv ve index arasinda $DIFF dosya farki var"
    else
        echo "   BASARILI: Arsiv ve index eslesme tamam"
    fi
fi

echo ""
echo "Dogrulama tamamlandi: $(date)"

Cron ile Otomatik Yedekleme ve Raporlama

Tüm bu parçaları bir araya getiren, production’da gerçekten kullanılabilir bir cron senaryosu:

#!/bin/bash
# /usr/local/bin/smart_backup.sh
# Cron: 0 2 * * * /usr/local/bin/smart_backup.sh >> /var/log/backup/cron.log 2>&1

set -euo pipefail

BACKUP_DATE=$(date +%Y%m%d)
BACKUP_HOUR=$(date +%H%M)
BACKUP_DIR="/mnt/backup/daily"
LOG_DIR="/var/log/backup"
RETENTION_DAYS=30
NOTIFY_EMAIL="[email protected]"

mkdir -p "$BACKUP_DIR" "$LOG_DIR"

BACKUP_FILE="$BACKUP_DIR/sistem_${BACKUP_DATE}_${BACKUP_HOUR}.tar.gz"
LOG_FILE="$LOG_DIR/backup_${BACKUP_DATE}_${BACKUP_HOUR}.log"
INDEX_FILE="$LOG_DIR/index_${BACKUP_DATE}_${BACKUP_HOUR}.txt"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

log "Yedekleme basliyor: $BACKUP_FILE"
START_TIME=$(date +%s)

# Yedekleme
tar 
    --checkpoint=2000 
    --checkpoint-action=echo="[$(date '+%H:%M:%S')] Blok %u islendi" 
    --exclude='/var/cache' 
    --exclude='*.log' 
    --exclude='/proc' 
    --exclude='/sys' 
    --exclude='/tmp' 
    --index-file="$INDEX_FILE" 
    -czf "$BACKUP_FILE" 
    /etc /home /var/www /opt 
    2>&1 | tee -a "$LOG_FILE"

BACKUP_STATUS=${PIPESTATUS[0]}
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
DURATION_HUMAN=$(printf '%02d:%02d:%02d' $((DURATION/3600)) $((DURATION%3600/60)) $((DURATION%60)))

if [ $BACKUP_STATUS -eq 0 ]; then
    sha256sum "$BACKUP_FILE" > "${BACKUP_FILE}.sha256"
    
    BACKUP_SIZE=$(du -sh "$BACKUP_FILE" | cut -f1)
    FILE_COUNT=$(wc -l < "$INDEX_FILE")
    
    log "BASARILI: $BACKUP_SIZE, $FILE_COUNT dosya, Sure: $DURATION_HUMAN"
    
    # Eski yedekleri temizle
    find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
    log "Eski yedekler temizlendi (${RETENTION_DAYS} gun)"
    
    SUBJECT="[OK] Yedekleme tamamlandi - $(hostname) - $BACKUP_DATE"
    BODY="Boyut: $BACKUP_SIZEnDosya: $FILE_COUNTnSure: $DURATION_HUMAN"
else
    log "HATA: Yedekleme basarisiz! Kod: $BACKUP_STATUS"
    SUBJECT="[HATA] Yedekleme basarisiz - $(hostname) - $BACKUP_DATE"
    BODY="Hata kodu: $BACKUP_STATUSnLog: $LOG_FILE"
fi

echo -e "$BODY" | mail -s "$SUBJECT" "$NOTIFY_EMAIL" 2>/dev/null || true

Sonuç

tar’ın checkpoint mekanizması ilk bakışta küçük bir özellik gibi görünebilir ama doğru araçlarla (index-file, pv, özel checkpoint scriptleri) birleştirildiğinde ciddi bir yedekleme altyapısı kurmanızı sağlıyor.

Özetle dikkat edilmesi gereken noktalar:

  • Her zaman --index-file kullanın: Bu olmadan ne alındığını bilmeniz mümkün değil
  • Checkpoint action’ları log dosyasına yönlendirin: Sadece stdout’a yazmak yetmez, kesinti sonrası analiz için kayıt şart
  • Yedek aldıktan sonra doğrulayın: tar -tzf ile en azından arşiv bütünlüğünü kontrol edin
  • Disk doluluk kontrolünü atlamamın: Checkpoint handler script’e mutlaka ekleyin
  • Büyük veri setleri için önce filelist oluşturun: Hem daha kontrollü hem kurtarma senaryolarında hayat kurtarıcı

Bu tekniklerin hepsini birden ilk gün uygulamanıza gerek yok. --checkpoint ve --index-file ile başlayın, işe yarıyor dediğinizde diğer katmanları ekleyin. Sysadmin işinin güzelliği de bu zaten, her şeyi kademeli olarak olgunlaştırabiliyorsunuz.

Bir yanıt yazın

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