Arşivleme İşlemlerinde Sparse Dosyaları Yönetme: Delik İçeren Dosyaları tar ve cp ile Verimli Yedekleme
Yıllar önce bir müşterimizin production ortamında ciddi bir yedekleme sorunu yaşadık. Sanal makine disklerini her gece tar ile yedekliyorduk, her şey güzeldi, ta ki geri yükleme zamanı gelene kadar. Yedek boyutları disk üzerindeki gerçek kullanımın çok üzerindeydi ve restore işlemi saatler alıyordu. Sorunun kaynağı sparse dosyalardı. O günden bu yana sparse dosyaları anlamak ve doğru yönetmek benim için temel bir sysadmin yetkinliği haline geldi.
Sparse Dosya Nedir, Neden Önemlidir?
Sparse dosya (delikli dosya), içinde büyük boş alanlar (zero blok dizileri) bulunduran ama bu boş alanların diske fiziksel olarak yazılmadığı özel dosyalardır. Dosya sistemi, bu “delikleri” metadata olarak takip eder; sıfır bloklarını gerçekten depolamaz.
Bunu somutlaştıralım:
# 1GB boyutunda ama sadece birkaç KB gerçek veri içeren sparse dosya oluşturma
dd if=/dev/zero of=/tmp/sparse_test.img bs=1 count=0 seek=1G
ls -lh /tmp/sparse_test.img # Görünen boyut: 1GB
du -sh /tmp/sparse_test.img # Gerçek disk kullanımı: 4KB (veya 0)
Çıktı şuna benzer bir şey gösterir:
-rw-r--r-- 1 root root 1.0G Kas 15 09:23 /tmp/sparse_test.img
4.0K /tmp/sparse_test.img
ls size 1GB diyor, du ise 4KB. İşte bu fark sparse dosyaların özü. Sanal makine disk imajları (QEMU/KVM .qcow2 ham img dosyaları), veritabanı dosyaları, Docker katman dosyaları bunların hepsi sıklıkla sparse yapıdadır.
Sparse durumunu daha ayrıntılı görmek için:
# FIEMAP/FIBMAP ile delik haritasını çıkart
filefrag -v /tmp/sparse_test.img
# Daha okunaklı çıktı için
stat /tmp/sparse_test.img | grep -E "Size|Blocks"
# Size: 1073741824 Blocks: 8 IO Block: 4096
Blocks: 8 değeri, dosyanın disk üzerinde yalnızca 4096 baytlık (8 x 512 byte) gerçek blok kapladığını gösteriyor.
Sorunun Kaynağı: Naive Arşivleme
Burası kritik nokta. Varsayılan ayarlarla tar veya cp kullandığınızda ne olur?
# TEHLİKELİ: Sparse dosyayı olduğu gibi arşivle
tar -cvf /backup/sparse_test.tar /tmp/sparse_test.img
ls -lh /backup/sparse_test.tar
# Sonuç: ~1GB tar dosyası oluştu!
tar bu dosyayı arşivlerken delikleri doldurmak için sıfır baytlar yazdı ve 1GB’lık gerçek bir tar dosyası oluştu. 100 adet böyle VM disk imajınız varsa yedekleme sisteminiz geceleri 100GB yerine terabaytlar üretmeye başlar.
cp de aynı hatayı yapar:
# TEHLİKELİ: cp ile sparse özelliğini kaybetme
cp /tmp/sparse_test.img /backup/sparse_test_copy.img
du -sh /backup/sparse_test_copy.img
# 1.0G -- Tüm alan dolu!
tar ile Sparse Dosyaları Doğru Yedekleme
tar komutunun bu sorunu çözecek özel bir parametresi var: -S veya --sparse.
# DOĞRU: Sparse-aware arşivleme
tar -cSvf /backup/sparse_test.tar /tmp/sparse_test.img
ls -lh /backup/sparse_test.tar
# Sonuç: ~10KB tar dosyası (sadece gerçek veri + metadata)
Bu kadar basit. -S bayrağı tar‘a “bu dosyadaki delikleri tespit et, sıfır bloklarını depolama, sadece pozisyon bilgisini kaydet” der.
Parametreler şöyle açıklanabilir:
-S: Sparse dosyaları algıla ve verimli şekilde depola-c: Yeni arşiv oluştur-v: Verbose mod, işlemleri listele-f: Çıktı dosyasını belirt
Sıkıştırma ile birlikte kullanım:
# Sparse + gzip sıkıştırma
tar -cSzvf /backup/vm_disks.tar.gz /var/lib/libvirt/images/
# Sparse + bzip2 (daha iyi sıkıştırma, daha yavaş)
tar -cSjvf /backup/vm_disks.tar.bz2 /var/lib/libvirt/images/
# Sparse + xz (en iyi sıkıştırma, en yavaş)
tar -cSJvf /backup/vm_disks.tar.xz /var/lib/libvirt/images/
Önemli not: Sıkıştırma algoritmaları zaten sıfır byte dizilerini çok iyi sıkıştırır. Dolayısıyla -Sz kombinasyonu çoğu zaman iyi sonuç verir ama -S olmadan yapılan sıkıştırmada CPU’yu boşuna yorarsınız.
Geri Yükleme Sırasında Sparse Yapıyı Koruma
Arşivden çıkarırken de sparse özelliğini korumak gerekir:
# Sparse yapıyı koruyarak geri yükle
tar -xSvf /backup/sparse_test.tar -C /restore/
# Kontrol et
ls -lh /restore/sparse_test.img # Görünen: 1GB
du -sh /restore/sparse_test.img # Gerçek: ~4KB
-S hem arşivleme hem çıkarma sırasında çalışır. Çıkarma sırasında tar, arşivde kayıtlı delik pozisyonlarını okuyarak dosyayı yeniden sparse olarak oluşturur.
cp ile Sparse Dosyaları Kopyalama
cp komutunda sparse davranışını --sparse seçeneği kontrol eder:
--sparse=always: Her zaman sparse dosya oluşturmaya çalış (sıfır blokları delik haline getir)--sparse=never: Hiçbir zaman sparse oluşturma, her şeyi yaz--sparse=auto: Varsayılan, kaynak sparse ise hedefi de sparse yap
# Sparse özelliğini koruyarak kopyala
cp --sparse=always /tmp/sparse_test.img /backup/sparse_copy.img
# Doğrula
du -sh /backup/sparse_copy.img # Küçük göstermeli
ls -lh /backup/sparse_copy.img # Büyük göstermeli
--sparse=always seçeneği özellikle ilginç: Kaynak sparse olmasa bile, hedef dosyada sıfır bloklarını gerçek blok yerine delik olarak yazar. Bu şu anlama gelir: Büyük bir veritabanı dump dosyasını kopyalarken bile boş alanları sparse’a dönüştürebilirsiniz.
# Sparse olmayan bir dosyayı sparse hale getirerek kopyala
dd if=/dev/zero of=/tmp/non_sparse.img bs=1M count=100
du -sh /tmp/non_sparse.img # 100MB
cp --sparse=always /tmp/non_sparse.img /tmp/converted_sparse.img
du -sh /tmp/converted_sparse.img # Muhtemelen 4KB veya daha az
Gerçek Dünya Senaryosu: KVM Sanal Makine Yedekleme
Benim en çok kullandığım alan KVM/libvirt ortamlarıdır. Production’da onlarca sanal makine varken yedekleme stratejisi ciddi önem kazanır.
#!/bin/bash
# kvm_backup.sh - KVM disk imajlarını sparse-aware yedekle
BACKUP_DIR="/mnt/backup/kvm"
IMAGE_DIR="/var/lib/libvirt/images"
DATE=$(date +%Y%m%d_%H%M%S)
LOG="/var/log/kvm_backup.log"
mkdir -p "$BACKUP_DIR"
echo "[$DATE] Backup başladı" >> "$LOG"
for img in "$IMAGE_DIR"/*.img "$IMAGE_DIR"/*.qcow2; do
[ -f "$img" ] || continue
basename=$(basename "$img")
backup_file="$BACKUP_DIR/${basename}_${DATE}.tar.xz"
echo "Yedekleniyor: $basename" | tee -a "$LOG"
# Sparse-aware tar ile yedekle
tar -cSJvf "$backup_file" -C "$IMAGE_DIR" "$basename" 2>> "$LOG"
if [ $? -eq 0 ]; then
original_size=$(du -sh "$img" | cut -f1)
backup_size=$(du -sh "$backup_file" | cut -f1)
echo "Tamamlandı: $basename | Gerçek: $original_size | Yedek: $backup_size" | tee -a "$LOG"
else
echo "HATA: $basename yedeklenemedi!" | tee -a "$LOG"
fi
done
echo "[$DATE] Backup tamamlandı" >> "$LOG"
Bu script’i cron’a ekleyip gece yarısı çalıştırabilirsiniz. Sıfır bayrak olmadan yapılan yedeklemeyle kıyasladığınızda disk tasarrufu dramatik olacaktır.
rsync ile Sparse Dosya Senkronizasyonu
rsync de sparse dosyalar için özel destek sunar. -S veya --sparse bayrağı burada da aynı görevi görür:
# rsync ile sparse-aware senkronizasyon
rsync -avS /var/lib/libvirt/images/ backup-server:/backup/kvm/
# Uzak sunucuya sparse dosya transfer et
rsync -avS --progress /tmp/sparse_test.img user@remote:/backup/
# Bant genişliği sıkıştırması ile birlikte
rsync -avSz /var/lib/libvirt/images/ backup-server:/backup/kvm/
Parametreler:
-a: Archive mod (izinler, timestamps, sembolik linkler korunur)-v: Verbose-S: Sparse dosyaları verimli ilet-z: Transfer sırasında sıkıştır
Dikkat: -S ve -z birlikte kullanıldığında rsync önce sıkıştırır, bu da sparse tespitini zorlaştırabilir. Yerel ağda -S yeterlidir; WAN üzerinde -Sz kombinasyonu dengeyi test edilerek kullanılmalıdır.
Sparse Dosya Analizi ve Tanı Araçları
Bir dosyanın sparse olup olmadığını ve ne kadar “delikli” olduğunu anlamak için birkaç araç işe yarar:
# Dosya sistem bloğu bilgisi
stat /tmp/sparse_test.img
# Parça haritası (extent map)
filefrag -v /tmp/sparse_test.img
# Gerçek ve görünen boyut farkını hesapla
apparent=$(ls -s --block-size=1 /tmp/sparse_test.img | awk '{print $1}')
actual=$(stat --format="%b * %B" /tmp/sparse_test.img | bc)
echo "Görünen: $apparent bytes"
echo "Gerçek: $actual bytes"
echo "Tasarruf: $(( (apparent - actual) * 100 / apparent ))%"
# Dizin içindeki tüm sparse dosyaları bul
find /var/lib/libvirt/images -type f -exec bash -c '
apparent=$(ls -s --block-size=512 "$1" | awk "{print $1}")
actual=$(stat --format="%b" "$1")
if [ "$actual" -lt "$apparent" ]; then
echo "SPARSE: $1 (görünen: $apparent blok, gerçek: $actual blok)"
fi
' _ {} ;
Bu son komut biraz ağır ama büyük bir storage sunucusunda hangi dosyaların sparse olduğunu listelemek için kullanışlı.
Dosya Sistemi Uyumluluğu Meselesi
Sparse dosyalar her dosya sisteminde aynı verimde çalışmaz. Bazı önemli notlar:
- ext4: Tam sparse desteği, en yaygın kullanım
- XFS: Mükemmel sparse desteği, büyük dosyalar için tercih edilir
- Btrfs: Sparse destekler, ayrıca COW özelliği ile sparse kullanımı verimli
- FAT32/exFAT: Sparse desteği yok, tüm sıfırlar yazılır
- NTFS (Linux’ta): Sınırlı sparse desteği
- NFS: Sunucuya bağlıdır
# Hedef dosya sisteminin sparse destekleyip desteklemediğini test et
test_sparse_support() {
local target_dir="$1"
local test_file="$target_dir/.sparse_test_$$"
dd if=/dev/zero of="$test_file" bs=1 count=0 seek=1M 2>/dev/null
actual_blocks=$(stat --format="%b" "$test_file")
rm -f "$test_file"
if [ "$actual_blocks" -eq 0 ] || [ "$actual_blocks" -eq 8 ]; then
echo "$target_dir: Sparse DESTEKLENIYOR"
return 0
else
echo "$target_dir: Sparse DESTEKLENMIYOR (blok sayısı: $actual_blocks)"
return 1
fi
}
test_sparse_support /backup
test_sparse_support /mnt/nas_backup
Yedekleme Doğrulama: Bütünlük Kontrolü
Sparse yedeklemelerden sonra mutlaka bütünlük kontrolü yapın:
#!/bin/bash
# sparse_backup_verify.sh
BACKUP_FILE="$1"
if [ -z "$BACKUP_FILE" ]; then
echo "Kullanım: $0 <backup_dosyasi.tar.xz>"
exit 1
fi
echo "=== Yedek Dosya Bilgisi ==="
ls -lh "$BACKUP_FILE"
du -sh "$BACKUP_FILE"
echo ""
echo "=== Arşiv İçeriği ==="
tar -tSJvf "$BACKUP_FILE"
echo ""
echo "=== Bütünlük Testi ==="
if tar -tSJf "$BACKUP_FILE" > /dev/null 2>&1; then
echo "BAŞARILI: Arşiv bütünlüğü doğrulandı"
else
echo "HATA: Arşiv bozuk olabilir!"
exit 1
fi
# MD5 checksum
echo ""
echo "=== Checksum ==="
md5sum "$BACKUP_FILE"
Pratik Özet ve Öneriler
Production’da bu konuda öğrendiklerimi maddeler halinde bırakayım:
- Her zaman
-Skullanın:tarile VM disk, veritabanı dosyası veya herhangi büyük binary dosya yedeklerken-Sbayrağını atlamamak alışkanlık haline getirin duvslsfarkını anlayın: Disk kullanımını her zamanduile kontrol edin,ls -lhyanıltıcıdır- Hedef dosya sistemi önemli: NAS’a veya USB disk’e yedek alırken hedefin sparse destekleyip desteklemediğini test edin
- cp’de
--sparse=alwaysgüçlüdür: Sparse olmayan büyük dosyaları da dönüştürmek için kullanılabilir - rsync ile uzak yedeklerde
-Sekleyin: Aksi hâlde hem bant genişliğini hem uzak disk alanını boşa kullanırsınız - Geri yükleme testini unutmayın: Sadece yedek almak yetmez, düzenli aralıklarla geri yükleme testi yaparak sparse yapının korunduğunu doğrulayın
Sonuç
Sparse dosyalar, sistem yöneticiliğinde görünmez ama son derece etkili bir konudur. Yanlış yönetildiğinde yedekleme sistemlerinizin diskini gereksiz yere doldurur, yedek transferlerini yavaşlatır ve geri yükleme sürelerini uzatır. Doğru yönetildiğinde ise önemli miktarda disk alanı ve bant genişliği tasarrufu sağlar.
tar -S, cp --sparse=always ve rsync -S üçlüsünü iş akışınıza dahil etmek için gereken tek şey bunları bir kere doğru anlamak ve alışkanlık hâline getirmek. Özellikle KVM/QEMU ortamlarında, büyük veritabanı yedeklemelerinde ve Docker depolama katmanlarıyla çalışırken bu bilgi doğrudan operasyonel maliyetlerinizi etkiler.
Konu basit görünebilir ama yıllar içinde gördüm ki bu “küçük” detayı atlamak, terabaytlık gereksiz yedek verisiyle sonuçlanabiliyor. Bir kere öğren, her zaman uygula.
