Arşivleme İşlemlerinde Deduplication: Yinelenen Dosyaları Tespit Edip Arşiv Boyutunu Küçültme

Yıllar içinde en çok canımı sıkan şeylerden biri, depolama alanının neden bu kadar hızlı dolduğunu anlamamaktı. Bir gün sunucuya bakıyorsun, 2 TB’lık disk %90 dolu. Yedekleme dizinine giriyorsun, onlarca backup_final.tar.gz, backup_final_v2.tar.gz, backup_son_hali.tar.gz dosyası sıralanmış. Hepsini açıp karşılaştırıyorsun, içerik neredeyse aynı. İşte bu noktada deduplication konusu hayat kurtarıcı hale geliyor.

Deduplication, Türkçeyle “yineleme giderme” ya da “tekilleştirme” diyebileceğimiz bir kavram. Arşivleme bağlamında bakıldığında, birden fazla yerde aynı içeriğe sahip dosyaların ya da veri bloklarının tespit edilip tekrar eden kısımların depolanmasından vazgeçilmesi anlamına geliyor. Bu yazıda sıfırdan bir yaklaşım sunacağım: önce yinelenen dosyaları nasıl bulursunuz, sonra bu bilgiyi arşivleme sürecinde nasıl kullanırsınız, ve gerçek senaryolarda ne gibi araçlar işe yarıyor.

Yinelenen Dosyaları Tespit Etmek: Temel Yaklaşım

Bir dosyanın “aynı” olup olmadığını anlamanın en güvenilir yolu ismine ya da boyutuna bakmak değil, içeriğinin hash değerine bakmaktır. İki dosya isim olarak tamamen farklı olabilir ama MD5, SHA1 ya da SHA256 değerleri aynıysa içerik birebir aynıdır.

Linux’ta bunu yapmak için birkaç farklı yol var. En basit yöntemle başlayalım:

find /yedek/dizin -type f | xargs md5sum | sort | awk 'seen[$1]++ {print $2, "DUPLIKAT"}'

Bu komut şu işi yapıyor: belirtilen dizin altındaki tüm dosyaların MD5 hash değerini hesaplıyor, ardından aynı hash’e sahip olanları awk ile işaretliyor. Çıktıda DUPLIKAT yazan satırlar, daha önce görülen bir hash’in tekrarıdır.

Ama bu yeterince temiz bir çıktı değil. Daha okunabilir bir sonuç için şu şekilde geliştirebiliriz:

find /yedek/dizin -type f -exec md5sum {} + | 
  sort | 
  awk '{
    hash=$1; $1=""; dosya=substr($0,2)
    if (onceki_hash == hash) {
      if (!grup_baslatildi) { print "--- Grup ---"; print onceki_dosya; grup_baslatildi=1 }
      print dosya
    } else {
      grup_baslatildi=0
    }
    onceki_hash=hash; onceki_dosya=dosya
  }'

Bu biraz daha karmaşık görünebilir ama çıktı çok daha anlamlı: aynı içeriğe sahip dosyaları gruplar halinde listeler.

fdupes: Dedike Araç, Sade Kullanım

Yukarıdaki shell one-liner’ları işe yarıyor ama pratikte fdupes gibi bir araç çok daha hızlı ve güvenilir. Çoğu dağıtımda paket deposunda mevcut:

# Debian/Ubuntu
sudo apt install fdupes

# RHEL/CentOS/Rocky
sudo dnf install fdupes

# Arch
sudo pacman -S fdupes

Kurulum sonrası temel kullanım gayet sade:

fdupes -r /yedek/dizin

-r: Alt dizinleri de tarar (recursive)

Çıktıda her grup için aynı içeriğe sahip dosyaların listesi gelir. Ama benim asıl sevdiğim parametre -S: dosya boyutlarını da gösterir, böylece ne kadar alan kurtarabileceğinizi hemen görürsünüz.

fdupes -rS /yedek/dizin

Yinelenen dosyaları otomatik silmek istiyorsanız -d parametresi devreye girer, ama dikkatli olun: her gruptan birini interaktif olarak seçmenizi ister.

fdupes -rd /yedek/dizin

Eğer her gruptan ilk dosyayı otomatik tutup diğerlerini silmek istiyorsanız (CI/CD pipeline’larında ya da script içinde kullanım için):

fdupes -rdN /yedek/dizin

-N: En az interaksiyon modunda çalışır, her gruptan ilk dosyayı korur, diğerlerini siler. Bunu production’da çalıştırmadan önce mutlaka -r ile önce ne silineceğini görün.

rdfind: Büyük Dizinlerde Daha Hızlı Alternatif

fdupes küçük ve orta ölçekli dizinlerde mükemmel çalışır. Ama milyonlarca dosya içeren bir depo arşivini tararken biraz ağır kalabiliyor. Bu durumda rdfind daha iyi bir tercih:

sudo apt install rdfind

rdfind -dryrun true /yedek/dizin

-dryrun true parametresi herhangi bir değişiklik yapmadan sadece ne yapacağını raporlar. Çıktı dosyası olarak results.txt oluşturur:

rdfind -dryrun true /veri/arsiv 2>&1 | tail -20

Gerçekten silmek ya da hardlink oluşturmak istiyorsanız:

# Yinelenen dosyaları hardlink ile değiştir (disk alanı kazanılır, dosyalar silinmez)
rdfind -makehardlinks true /yedek/dizin

# Ya da sembolik link
rdfind -makesymlinks true /yedek/dizin

Hardlink yaklaşımı özellikle çok değerli: dosyalar hala her iki konumdan da erişilebilir görünür, ama diskte tek kopya tutulur. Yedekleme sistemleriyle çalışırken bu genellikle en güvenli seçenek.

Gerçek Dünya Senaryosu: Geliştirici Artefakt Deposu

Bir yazılım geliştirme ekibi düşünün. Her gün CI/CD sistemi build artefaktları üretiyor: JAR dosyaları, Docker katmanları, npm paketleri. Arşiv dizinine her sürüm için ayrı bir klasör oluşturuluyor.

/artefaktlar/
  v1.2.3/
    app.jar         (45 MB)
    config.xml      (2 KB)
    libs/           (120 MB, 200+ JAR)
  v1.2.4/
    app.jar         (45 MB, farklı)
    config.xml      (2 KB, aynı)
    libs/           (120 MB, 190 JAR aynı, 10 JAR farklı)

Bu durumda libs/ dizininin %95’i her sürümde aynı. fdupes ile analiz edelim:

fdupes -rS /artefaktlar/ > duplikat_raporu.txt
wc -l duplikat_raporu.txt

Sonuca bakınca genellikle şok edici rakamlar çıkıyor. 50 sürüm birikmiş bir depoda 30+ GB’lık tekrar eden veri görmek nadir değil.

Bu dosyaları hardlink haline getirmek için:

rdfind -makehardlinks true /artefaktlar/

Sonra gerçek disk kullanımını kontrol etmek için:

du -sh /artefaktlar/

du komutunun hardlink’leri nasıl saydığına dikkat edin: -l parametresi olmadan du, hardlink’leri ayrı saymaz, gerçek disk kullanımını gösterir.

Arşiv Oluştururken Deduplication: tar ve Özel Araçlar

Klasik tar ile arşiv oluştururken deduplication doğrudan desteklenmez. Ama bunu dolaylı yollarla yapabilirsiniz.

Yöntem 1: Önce hardlink, sonra tar

# Yinelenen dosyaları hardlink yap
rdfind -makehardlinks true /kaynak/dizin

# Ardından tar ile arşivle, hardlink'leri takip et
tar --hard-dereference -czf arsiv.tar.gz /kaynak/dizin

–hard-dereference: Hardlink’leri ayrı dosyalar olarak değil, bir kez arşive ekler.

Yöntem 2: Sıkıştırma algoritmasının yardımına güvenmek

Yinelenen veriler sıkıştırma açısından büyük fırsat sunar. gzip yerine zstd ya da xz kullanmak deduplication yönünden de avantajlı:

# xz ile maksimum sıkıştırma (yavaş ama küçük)
tar -cJf arsiv.tar.xz /kaynak/dizin

# zstd ile hızlı ve verimli sıkıştırma
tar -c /kaynak/dizin | zstd -19 -T0 -o arsiv.tar.zst

zstd ile -T0 tüm CPU çekirdeklerini kullanır. -19 maksimum sıkıştırma seviyesidir.

zpaq: Arşivleme ve Deduplication Bir Arada

zpaq, deduplication’ı arşiv formatının içine entegre etmiş bir araç. Incremental arşivleme yaparken blok düzeyinde deduplication uygular: aynı içeriğe sahip veri blokları, daha önce arşivlenmişse tekrar eklenmez.

sudo apt install zpaq

# İlk tam arşiv
zpaq add arsivim.zpaq /kaynak/dizin

# Bir hafta sonra, sadece değişenleri ekle (blok düzeyinde dedup ile)
zpaq add arsivim.zpaq /kaynak/dizin

# Arşiv içeriğini listele
zpaq list arsivim.zpaq

zpaq özellikle yedekleme senaryolarında parlıyor. Aynı dizini tekrar tekrar arşivliyorsanız ve dosyaların büyük kısmı değişmiyorsa, arşiv boyutunun nasıl küçüldüğünü görmek oldukça tatmin edici.

Büyük Ölçekli Senaryo: Log Arşivleri

Operasyonel ekiplerin sık yaşadığı bir durum: aylık log arşivleri. Her sunucudan gelen logları bir merkezi dizinde tutuyorsunuz:

/log-arsiv/
  2024-01/
    web01.log.gz
    web02.log.gz
    db01.log.gz
  2024-02/
    ...

Web sunucularından gelen logların büyük kısmı benzer yapıda: aynı statik dosyalara yapılan GET istekleri, aynı hata mesajları, benzer IP aralıkları. Burada dosya düzeyinde deduplication değil, blok düzeyinde deduplication daha mantıklı.

Önce mevcut durumu anlayalım:

# Toplam boyut
du -sh /log-arsiv/

# Ay ay kırılım
du -sh /log-arsiv/*/

# En büyük 20 dosya
find /log-arsiv -type f -name "*.gz" -exec du -sh {} + | 
  sort -rh | head -20

Sonra yinelenen dosyaları tespit et:

fdupes -r /log-arsiv/ > /tmp/duplikat_loglar.txt
cat /tmp/duplikat_loglar.txt | grep -c "^$"

Boş satır sayısı, kaç grup yinelenen dosya olduğunu verir.

Şimdi bu bilgiyle ne yapacağız? Log arşivlerini doğrudan silmek tehlikeli olabilir (compliance gereksinimleri, audit trail vs.). Bunun yerine hardlink kullanmak daha güvenli:

# Önce yedek al
cp -a /log-arsiv/ /log-arsiv-yedek/

# Hardlink ile deduplication
rdfind -makehardlinks true /log-arsiv/

# Kazanımı ölç
du -sh /log-arsiv/

sha256sum ile Güvenilir Hash Tabanlı Tespit

Kritik dosyalar söz konusu olduğunda MD5’e güvenmek istemeyebilirsiniz (collision riskleri açısından). SHA256 kullanmak daha güvenli:

find /kritik/arsiv -type f | sort | xargs sha256sum | 
  awk '{print $1}' | sort | uniq -d

Bu komut sadece yinelenen hash değerlerini basar. Hangi dosyaların bu hash’lere sahip olduğunu görmek için:

find /kritik/arsiv -type f -exec sha256sum {} + | 
  sort -k1 > /tmp/hash_listesi.txt

awk '{print $1}' /tmp/hash_listesi.txt | 
  sort | uniq -d > /tmp/tekrarlanan_hashler.txt

while read hash; do
  echo "=== $hash ==="
  grep "^$hash" /tmp/hash_listesi.txt | awk '{print $2}'
done < /tmp/tekrarlanan_hashler.txt

Bu script, her yinelenen hash için hangi dosyaların aynı içeriğe sahip olduğunu güzel bir şekilde raporlar.

Arşiv Boyutunu Ölçmek ve Karşılaştırmak

Deduplication uygulamadan önce ve sonra boyutu karşılaştırmak için birkaç yöntem:

# Gerçek disk kullanımı (hardlink'ler bir kez sayılır)
du -sh /arsiv/

# Her dosyanın boyutu dahil toplam (hardlink'ler çift sayılır)
du -slh /arsiv/

# İnod sayısı (hardlink olan dosyalar aynı inod'u paylaşır)
df -i /arsiv/

Deduplication oranını hesaplamak için basit bir script:

#!/bin/bash
DIZIN=${1:-"/arsiv"}

MANTIKSAL=$(find "$DIZIN" -type f -exec du -b {} + | awk '{t+=$1} END {print t}')
FIZIKSEL=$(du -sb "$DIZIN" | awk '{print $1}')

echo "Mantıksal boyut: $(numfmt --to=iec $MANTIKSAL)"
echo "Fiziksel boyut: $(numfmt --to=iec $FIZIKSEL)"
echo "Tasarruf oranı: $(echo "scale=1; (1 - $FIZIKSEL/$MANTIKSAL) * 100" | bc)%"

Bu script’i çalıştırmak için:

chmod +x dedup_rapor.sh
./dedup_rapor.sh /log-arsiv/

Dikkat Edilmesi Gereken Noktalar

Deduplication uygulamadan önce birkaç önemli noktayı aklınızda tutun:

  • Hardlink sınırları: Ext4 üzerinde bir inode maksimum 65000 hardlink’e sahip olabilir. Çok büyük depolarda bu limite takılabilirsiniz.
  • Yedekleme araçlarıyla uyum: rsync, Bacula, Amanda gibi araçlar hardlink’leri farklı şekilde işler. Deduplication uygulamadan önce yedekleme sisteminizin davranışını test edin.
  • Değişebilir dosyalar: Hardlink’lediğiniz iki dosyadan biri değişirse, diğeri de değişir. Bu bazen istenen, bazen istenmeyen bir davranış. Eğer dosyalar yalnızca okunacaksa sorun yok; ama yazılabilir dosyalarda dikkatli olun.
  • ZFS veya Btrfs kullanıyorsanız: Bu dosya sistemleri native deduplication sunuyor. Özellikle ZFS’in dedup özelliği blok düzeyinde çalışır ve ayrıca araç kullanmanıza gerek kalmaz. Ama ZFS dedup RAM’e ciddi yük bindirir, bunu da hesaba katın.
  • Boyuta göre ön filtreleme: fdupes varsayılan olarak önce dosya boyutlarını karşılaştırır, farklı boyuttaki dosyaların hash’ini bile hesaplamaz. Bu bir optimizasyon. Kendi script’lerinizde de bu yaklaşımı kullanın.

Sonuç

Arşivleme süreçlerinde deduplication, özellikle büyük ve uzun süredir büyüyen depolarda dramatik alan tasarrufu sağlayabiliyor. Benim deneyimlerimde geliştirici artefakt depolarında %40-60, log arşivlerinde %20-35 civarında alan kazanımı görmek nadir değil.

Pratik bir yaklaşım önerisinde bulunacak olursam: önce fdupes -rS ile mevcut durumu analiz edin, ne kadar yineleme var görmek için vakit ayırın. Sonra hardlink stratejisini rdfind ile uygulayın. Arşiv oluştururken zstd ya da xz kullanın; bu sıkıştırma algoritmaları kendi içlerinde yinelenen veri bloklarını çok iyi sıkıştırır.

Ölçmeden, anlamadan silmeye kalkışmak her zaman riskli. Bu yazıdaki araçların büyük kısmı önce raporlama, sonra aksiyon mantığıyla çalışıyor, bu kasıtlı bir tasarım. Sysadmin olarak “önce anla, sonra uygula” prensibi disk yönetiminde de geçerli.

Bir yanıt yazın

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