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-filekullanı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 -tzfile 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.
