Sparse Dosyalar: Seyrek Dosya Oluşturma, Algılama ve Disk Tasarrufu Teknikleri
Disk alanı konusunda çalışırken sparse dosyalar muhtemelen en çok “neden bu dosya bu kadar yer kaplıyor ki?” sorusunu cevaplayacak kavramlardan biri. Ben bu konuyla ilk ciddi şekilde karşılaştığımda sanal makine imajları üzerinde çalışıyordum ve du ile ls -lh çıktıları arasındaki uçurum beni epey şaşırtmıştı. Gelin bu konuya gerçekten pratik bir bakış açısıyla girelim.
Sparse Dosya Nedir?
Sparse dosya, içinde büyük boşluk blokları barındıran ama bu boşluklar için disk üzerinde fiziksel alan ayırmayan bir dosya türüdür. Dosya sistemi, bu “delik” bölgelerini metadata olarak saklar ve ilgili bloklar okunmaya çalışıldığında sıfır bayt döndürür.
Bunu şöyle düşünebilirsiniz: 100 GB’lık bir dosyanız var ama içinde sadece başta ve sonda birkaç KB gerçek veri var, geri kalan her şey sıfır. Sparse olmayan bir dosyada bu 100 GB diskinizi doldururdu. Sparse dosyada ise sadece gerçek veri içeren bloklar yer kaplar.
Bu özelliği destekleyen dosya sistemleri arasında ext2/3/4, XFS, Btrfs, ZFS ve NTFS bulunuyor. FAT32 desteklemez, bu yüzden USB bellekler arasında sparse dosyaları taşırken dikkatli olmanız gerekir.
Sparse Dosya Nerede Kullanılır?
Gerçek hayatta sparse dosyalarla en çok şu alanlarda karşılaşırsınız:
- Sanal makine disk imajları: QEMU/KVM’in kullandığı raw ve qcow2 formatları, VMware VMDK dosyaları
- Konteyner katmanları: Docker bazı storage driver’larında sparse dosya kullanır
- Veritabanı dosyaları: PostgreSQL ve bazı konfigürasyonlarda MySQL önceden alan ayırır ama hepsini kullanmaz
- Checkpoint ve snapshot dosyaları: Yedekleme araçları bu teknikten yoğun şekilde faydalanır
- Test ortamları: 1 TB’lık disk simüle etmek istiyorsunuz ama gerçekten 1 TB boş alanınız yok
Sparse Dosya Oluşturma
dd ile Sparse Dosya
En klasik yöntem dd kullanmak. Şu iki komut arasındaki farka dikkat edin:
# Bu sparse DEĞİL, gerçekten 10 GB yazar
dd if=/dev/zero of=buyuk_dosya_normal.img bs=1M count=10240
# Bu sparse, sadece metadata yazar, anında tamamlanır
dd if=/dev/zero of=buyuk_dosya_sparse.img bs=1M count=0 seek=10240
seek parametresi burada sihri yapıyor. Yazma başlangıç noktasını 10240 blok (yani 10 GB) ileriye alıyoruz ve count=0 ile hiç veri yazmıyoruz. Sonuçta dosya 10 GB boyutunda görünür ama diskte neredeyse hiç yer kaplamaz.
truncate ile Sparse Dosya
truncate komutu bu iş için daha temiz ve anlaşılır bir arayüz sunuyor:
# 50 GB sparse dosya oluştur
truncate -s 50G test_disk.img
# 1 TB'lık bir "disk" simüle et
truncate -s 1T simulated_disk.img
# Dosyayı büyüt (mevcut içeriği koruyarak)
truncate -s 100G mevcut_dosya.img
truncate ile oluşturulan dosyalar her zaman sparse olarak başlar. Sonradan bu dosyaya veri yazarsanız, yazılan bölgeler gerçek disk alanı kullanmaya başlar.
fallocate ile Farklı Yaklaşımlar
fallocate hem sparse hem de pre-allocated dosyalar için kullanılabilir, bu yüzden özellikle dikkat gerektiriyor:
# Pre-allocated dosya (disk alanını gerçekten ayırır, SPARSE DEĞİL)
fallocate -l 10G prealloc_dosya.img
# Punch hole: Mevcut bir dosyada belirli bir aralığı sparse'a çevir
fallocate --punch-hole -o 1024 -l 4096 dosyam.img
# Dosyayı sparse yap (destekleyen filesystemlerde)
fallocate --collapse-range -o 0 -l 512 dosyam.img
Buradaki --punch-hole özelliği son derece güçlü. Büyük bir dosyanın ortasındaki sıfır bloklarını diskte gerçekten serbest bırakabilirsiniz. Yedekleme araçlarının “deduplication” yaparken kullandığı teknik tam da bu.
Sparse Dosyaları Algılama
Bu kısım pratikte en çok işe yarayan kısım. Sistemde sparse dosya olup olmadığını anlamak için birkaç yöntem var.
du ve ls Farkı
# Bir dosya için her iki komutu da çalıştırın
ls -lh buyuk_dosya_sparse.img
du -sh buyuk_dosya_sparse.img
# Örnek çıktılar:
# ls: 10G (görünür boyut)
# du: 4.0K (gerçek disk kullanımı)
Eğer ls -lh çıktısı ile du -sh çıktısı arasında büyük fark varsa, sparse dosyayla karşı karşıyasınız demektir. Bu basit kontrol beni defalarca kurtardı.
stat Komutu ile Detaylı Bilgi
stat buyuk_dosya_sparse.img
Çıktıda şunlara bakın:
- Size: Dosyanın mantıksal boyutu
- Blocks: Gerçekte tahsis edilmiş 512 byte’lık blok sayısı
- IO Block: Filesystem blok boyutu
Eğer Blocks değeri beklediğinizden çok küçükse, dosya sparse’dır. Matematiksel olarak: Blocks * 512 << Size ise sparse dosyasınız.
find ile Sistemdeki Sparse Dosyaları Bulma
# Sparse dosyaları bul (görünür boyut > gerçek boyut olanlar)
find /var/lib/libvirt -name "*.img" -printf "%s %k %pn" |
awk '{if ($1 > $2*1024) print $3, "SPARSE:", $1, "vs", $2*1024}'
# Daha basit yaklaşım: belirli dizinde sparse dosya tarama
find /home -type f -printf "%s %b %pn" |
awk '{apparant=$1; actual=$2*512; if(apparant > actual*1.1) print $3}'
find komutundaki %k formatı, gerçek disk kullanımını KB cinsinden verir. %s ise byte cinsinden görünür boyutu verir. Bu ikisini karşılaştırarak sparse dosyaları tespit edebilirsiniz.
Sparse Dosyaları Kopyalama: Dikkat Edilmesi Gereken Nokta
En sık yapılan hata sparse dosyaları normal cp ile kopyalamak. Bunu yaparsanız sparse özelliği kaybolur ve tüm sıfır blokları da diske yazılır:
# YANLIŞ: 10 GB sparse dosyayı kopyalar, hedef 10 GB yer kaplar
cp buyuk_dosya_sparse.img kopya.img
# DOĞRU: Sparse özelliğini koruyarak kopyala
cp --sparse=always buyuk_dosya_sparse.img kopya_sparse.img
# rsync ile sparse koruma
rsync -avS kaynak.img hedef.img
# rsync ile detaylı seçenekler
rsync --sparse --progress --stats kaynak/ hedef/
rsync komutundaki -S veya --sparse bayrağı sparse dosyaları akıllıca işler. Özellikle sanal makine imajlarını bir sunucudan diğerine taşırken bu bayrak hem transfer süresini hem de disk kullanımını dramatik şekilde düşürür. 50 GB’lık bir VM imajını sadece 2 GB gerçek veriyle taşıdığım oldu, ağ üzerinden.
Pratik Senaryo: VM Disk İmajı Yönetimi
QEMU/KVM ortamında bu bilgiler son derece kritik. Şöyle bir durum düşünün: 500 GB kapasiteli ama sadece 30 GB dolu bir VM’iniz var.
# VM disk imajının durumunu kontrol et
qemu-img info /var/lib/libvirt/images/sunucu01.qcow2
# Raw imaj ise sparse kontrolü
ls -lh /var/lib/libvirt/images/sunucu01.raw
du -sh /var/lib/libvirt/images/sunucu01.raw
# qcow2'yi sparse raw'a dönüştür
qemu-img convert -O raw -S 4k
kaynak.qcow2 hedef_sparse.raw
# Sparse raw'ı tekrar qcow2'ye dönüştür (sıkıştırmak için)
qemu-img convert -c -O qcow2
hedef_sparse.raw sikistirilmis.qcow2
qemu-img convert komutundaki -S 4k parametresi, 4 KB’dan küçük sparse bölümleri bile tespit ederek çıktıda sparse dosya oluşturmasını sağlar.
Sparse Dosyaları Sıkıştırma ve Optimize Etme
Bazen sparse olmayan ama çok sayıda sıfır bloğu olan dosyalarınız vardır. Bunları sparse hale getirmek disk alanı kurtarır:
# Bir dosyadaki sıfır bloklarını tespit et ve sparse yap
# (sparse-detect betiği örneği)
python3 -c "
import os, sys
fname = sys.argv[1]
block_size = 4096
with open(fname, 'r+b') as f:
offset = 0
f.seek(0, 2)
size = f.tell()
f.seek(0)
while offset < size:
block = f.read(block_size)
if block == b'x00' * len(block):
os.lseek(f.fileno(), offset, 0)
import ctypes
# punch hole işlemi
print(f'Zero block at offset {offset}')
offset += block_size
" dosyam.img
# Daha pratik: cp ile sparse'a dönüştür
cp --sparse=always kaynak_dense.img hedef_sparse.img
# Var olan bir dosyayı sparse hale getirmenin en pratik yolu
# (aynı filesystem üzerinde)
cp --sparse=always buyuk_dosya.img buyuk_dosya_sparse.img &&
mv buyuk_dosya_sparse.img buyuk_dosya.img
# Filesystem sparse desteğini kontrol et
lsattr -d /var/lib/libvirt/images/
Gerçek Hayat Senaryosu: Log Dosyaları ve Veritabanı Yönetimi
Bir gün bir müşterimizin sunucusunda disk doldu. df -h 98% kullanım gösteriyordu. du -sh /* ile köke indik, /var büyük çıktı, /var/lib/postgresql daha da büyük. Ama du -sh ile ls -lh arasındaki fark bizi şaşırttı: bazı PostgreSQL WAL dosyaları sparse görünüyordu.
# Hangi PostgreSQL dosyaları sparse?
find /var/lib/postgresql -type f -printf "%s %b %pn" |
awk '{if ($1 > $2*512) print $3, "boyut:", $1, "gercek:", $2*512}' |
sort -k4 -n -r | head -20
# WAL arşiv dosyalarını kontrol et
for f in /var/lib/postgresql/*/pg_wal/*; do
apparent=$(stat --format="%s" "$f")
actual=$(du -b "$f" | cut -f1)
if [ "$apparent" -gt "$((actual * 2))" ]; then
echo "SPARSE: $f (apparent: $apparent, actual: $actual)"
fi
done
Bu tür durumları erken tespit etmek, disk dolma krizlerini önler.
Monitoring: Sparse Dosya Farkındalığı
Sistemde sparse dosyaları izlemek için basit bir script:
#!/bin/bash
# sparse_monitor.sh
# Sistemdeki önemli sparse dosyaları raporlar
DIZINLER="/var/lib/libvirt /var/lib/docker /home /tmp"
ESIK=1073741824 # 1 GB'dan büyük farklar
echo "=== Sparse Dosya Raporu: $(date) ==="
echo ""
for dizin in $DIZINLER; do
[ -d "$dizin" ] || continue
echo "Dizin: $dizin"
find "$dizin" -type f -size +100M 2>/dev/null | while read dosya; do
apparent=$(stat --format="%s" "$dosya" 2>/dev/null)
blocks=$(stat --format="%b" "$dosya" 2>/dev/null)
actual=$((blocks * 512))
fark=$((apparent - actual))
if [ "$fark" -gt "$ESIK" ]; then
fark_gb=$(echo "scale=2; $fark/1073741824" | bc)
echo " [SPARSE] $dosya"
echo " Gorunen: $(numfmt --to=iec $apparent)"
echo " Gercek: $(numfmt --to=iec $actual)"
echo " Tasarruf: ${fark_gb} GB"
fi
done
echo ""
done
Bu script’i cron’a ekleyip haftalık rapor alabilirsiniz.
Windows Tarafı: NTFS Sparse Dosyalar
Linux’tan NTFS volume’lara erişirken sparse davranışı farklılaşabilir:
# NTFS üzerinde sparse dosya oluştur (ntfs-3g ile)
# Doğrudan Linux araçları çalışır, NTFS driver halleder
# Ancak NTFS'ten Linux'a kopyalarken dikkat
ntfscp /dev/sdb1 sparse_dosya.img /hedef/
# Daha güvenli yöntem
ntfscat /dev/sdb1 /sparse_dosya.img | cp --sparse=always /dev/stdin hedef.img
Windows Server yönetiyorsanız, PowerShell tarafında fsutil file querySparseRanges komutu ile sparse alanları görebilirsiniz. Ama bu başlı başına ayrı bir konu.
Sparse Dosyalarda Karşılaşılan Yaygın Sorunlar
- Arşivleme sorunları:
tarvarsayılan olarak sparse dosyaları sıradan dosya gibi arşivler.-Sbayrağını kullanın:tar -cSf arsiv.tar dosyalar/ - NFS üzerinden kopyalama: NFS sparse desteği kısıtlıdır, özellikle eski NFSv3’te. NFSv4.2 daha iyi sparse desteği sunar
- Yedekleme araçları: Bazı backup araçları sparse’ı yanlış hesaplayarak disk alanı yetersizliği hatası verebilir. Bacula, Amanda gibi araçlarda sparse-aware seçeneklerini aktif etmeyi unutmayın
- Scp ile taşıma:
scpsparse özelliğini korumaz, büyük sparse dosyalar içinrsync -Skullanın
# tar ile sparse koruma
tar -cSvf vm_backup.tar /var/lib/libvirt/images/
# tar'ı sparse-aware çıkartma
tar -xSvf vm_backup.tar
# Sparse dosyayı sıkıştırılmış arşive al
tar -cSzf vm_backup.tar.gz /var/lib/libvirt/images/
Sonuç
Sparse dosyalar doğru kullanıldığında ciddi disk tasarrufu sağlayan, anlık çalışan bir mekanizma. Özellikle sanallaştırma ortamlarında, test altyapılarında ve büyük veri boru hatlarında bu tekniği bilmek hem parayı hem zamanı kurtarır.
Özetlemek gerekirse en önemli noktalar şunlar:
truncate -sile hızlı sparse dosya oluşturunls -lhiledu -shfarkını kontrol ederek sparse dosyaları algılayın- Kopyalarken
cp --sparse=alwaysveyarsync -Skullanın tar -Sile sparse özelliğini arşivlerde koruyunfallocate --punch-holeile mevcut dosyalardaki boşlukları serbest bırakın
Disk alanı krizi yaşayan bir sistemde ilk yapacağım şeylerden biri hala find / -type f -printf "%s %b %pn" | awk '{if ($1 > $251210) print}' çalıştırmak. Hayatımı kaçkez kurtardığını saymakla geçerim.
