xdelta3 ve bsdiff ile Yama Tabanlı Dosya Güncelleme ve Delta Yedekleme

Büyük bir sistemde yüzlerce gigabaytlık veri yönetiyorsanız ve her güncelleme döngüsünde aynı dosyaları tekrar tekrar transfer etmek zorunda kalıyorsanız, delta tabanlı güncelleme kavramı size çok tanıdık gelecektir. Ben bu yöntemi ilk kez yaklaşık 10 yıl önce, bant genişliği kısıtlı bir üretim ortamında embedded cihaz firmware’lerini güncellemek zorunda kaldığımda keşfettim. O günden bu yana xdelta3 ve bsdiff araçları, araç çantamın vazgeçilmez parçaları haline geldi.

Delta Yama Mantığı Nedir?

Temel fikir son derece basit: iki dosya arasındaki farkı hesapla ve yalnızca bu farkı gönder. Alıcı taraf, elindeki eski dosyayı bu yamayla birleştirerek yeni versiyona ulaşır. Teoride harika, pratikte de gerçekten işe yarıyor.

Bu yöntem özellikle şu durumlarda hayat kurtarır:

  • Büyük binary dosyaların (firmware, veritabanı dump, disk imajı) güncellenmesi
  • Düşük bant genişlikli ortamlarda (uzak lokasyonlar, IoT cihazlar) dağıtım
  • Yedekleme boyutunu minimize etmek
  • CD/DVD imajları veya büyük arşiv dosyaları arasındaki farkları dağıtmak

xdelta3 ve bsdiff, bu alanda en yaygın kullanılan iki araçtır. Her ikisi de farklı algoritmalara dayanır ve farklı senaryolarda farklı verimlilik gösterirler.

xdelta3 Kurulumu ve Temel Kullanım

Çoğu dağıtımda xdelta3 doğrudan paket deposunda bulunur:

# Debian/Ubuntu
sudo apt install xdelta3

# RHEL/CentOS/Fedora
sudo dnf install xdelta3

# Arch Linux
sudo pacman -S xdelta3

bsdiff için durum biraz farklı. Bazı dağıtımlarda hazır paket var, bazılarında derlemeniz gerekebilir:

# Debian/Ubuntu
sudo apt install bsdiff

# Derleme gerekiyorsa (bzip2-dev bağımlılığıyla)
git clone https://github.com/mendsley/bsdiff
cd bsdiff
make
sudo cp bsdiff bspatch /usr/local/bin/

İlk Delta Yamanızı Oluşturmak

xdelta3 ile kullanım son derece düz. Diyelim ki uygulama_v1.bin adında bir dosyanız var ve bunu uygulama_v2.bin‘e dönüştürmek için bir yama üretmek istiyorsunuz:

# Yama oluşturma
xdelta3 -e -s uygulama_v1.bin uygulama_v2.bin uygulama_v1_to_v2.xdelta

# Yamayı uygulama
xdelta3 -d -s uygulama_v1.bin uygulama_v1_to_v2.xdelta uygulama_v2_restored.bin

# Doğrulama
md5sum uygulama_v2.bin uygulama_v2_restored.bin

Temel parametreler şunlar:

  • -e: Encode, yani yama oluşturma modu
  • -d: Decode, yani yamayı uygulama modu
  • -s: Kaynak (source) dosyayı belirtir
  • -f: Hedef dosya zaten varsa üzerine yaz
  • -v: Verbose, işlem detaylarını göster
  • -9: Maksimum sıkıştırma seviyesi (daha yavaş ama küçük yama)
  • -B: Kaynak pencere boyutunu belirtir (büyük dosyalar için kritik)

Büyük Dosyalar için Pencere Boyutu Ayarı

xdelta3’ün en çok gözden kaçan parametresi pencere boyutu. Varsayılan olarak yaklaşık 8MB’lık bir pencereyle çalışır. Büyük dosyalarda (birkaç GB üzeri) bu değeri artırmazsanız yama kalitesi ciddi ölçüde düşer:

# 256MB pencere boyutuyla büyük bir disk imajı için yama
xdelta3 -e -9 -B 268435456 -s sunucu_disk_v1.img sunucu_disk_v2.img disk_delta.xdelta

# Boyut karşılaştırması
ls -lh sunucu_disk_v2.img disk_delta.xdelta

Bunu öğrenmem de zahmetli oldu. Bir keresinde 4GB’lık bir database dump için yama oluşturdum, yama boyutu neredeyse orijinal dosyayla aynıydı. Sebebini araştırdığımda pencere boyutunu artırmam gerektiğini fark ettim. Pencereyi 512MB’a çıkardığımda yama boyutu %15’e düştü.

bsdiff: Binary Diff’in Ağır Topları

bsdiff, özellikle yürütülebilir dosyalar ve sıkıştırılmış binary’ler için xdelta3’ten daha iyi sonuç verir. Algoritması farklı: binary dosyalardaki yapısal benzerlikleri daha akıllıca tespit eder. Özellikle küçük kod değişikliklerinin binary’ye yansıması durumunda bsdiff çok daha küçük yamalar üretir.

# bsdiff ile yama oluşturma
bsdiff eski_uygulama yeni_uygulama uygulama.patch

# bspatch ile uygulama
bspatch eski_uygulama yeni_uygulama_restored uygulama.patch

# Doğrulama
sha256sum yeni_uygulama yeni_uygulama_restored

bsdiff’in dezavantajı bellek tüketimi. Kaynak ve hedef dosya boyutlarının toplamının yaklaşık 17 katı kadar RAM kullanabilir. 100MB’lık iki dosya için 1.7GB RAM düşünün. Üretim ortamında bunu göz önünde bulundurmanız şart.

Gerçek Dünya Senaryosu: Firmware Dağıtımı

Diyelim ki 500 adet IoT cihazınız var ve her birinde 32MB’lık bir firmware çalışıyor. Her ay yeni firmware çıkıyor, genellikle %5-10 oranında değişiklik var. Tam imajı göndermek yerine delta yama göndermek:

#!/bin/bash
# firmware_delta_creator.sh

FIRMWARE_DIR="/opt/firmware"
DELTA_DIR="/opt/firmware/deltas"
OLD_FW="$FIRMWARE_DIR/firmware_v2.3.bin"
NEW_FW="$FIRMWARE_DIR/firmware_v2.4.bin"
DELTA_FILE="$DELTA_DIR/fw_v2.3_to_v2.4.xdelta"

mkdir -p "$DELTA_DIR"

echo "Delta yama oluşturuluyor..."
xdelta3 -e -9 -B 33554432 -s "$OLD_FW" "$NEW_FW" "$DELTA_FILE"

OLD_SIZE=$(stat -c%s "$NEW_FW")
DELTA_SIZE=$(stat -c%s "$DELTA_FILE")
RATIO=$(echo "scale=2; $DELTA_SIZE * 100 / $OLD_SIZE" | bc)

echo "Orijinal boyut: $(du -sh $NEW_FW | cut -f1)"
echo "Delta boyutu: $(du -sh $DELTA_FILE | cut -f1)"
echo "Oran: %$RATIO"

# SHA256 checksum üret
sha256sum "$DELTA_FILE" > "$DELTA_FILE.sha256"
echo "Checksum oluşturuldu: $DELTA_FILE.sha256"

Cihaz tarafında da bir doğrulama mekanizması şart:

#!/bin/bash
# firmware_updater.sh (cihaz tarafı)

DELTA_URL="https://update.sirket.com/fw_v2.3_to_v2.4.xdelta"
CHECKSUM_URL="https://update.sirket.com/fw_v2.3_to_v2.4.xdelta.sha256"
CURRENT_FW="/flash/firmware_current.bin"

# Delta ve checksum indir
wget -q "$DELTA_URL" -O /tmp/firmware.xdelta
wget -q "$CHECKSUM_URL" -O /tmp/firmware.xdelta.sha256

# Checksum doğrula
if ! sha256sum -c /tmp/firmware.xdelta.sha256; then
    echo "HATA: Checksum doğrulaması başarısız!" >&2
    exit 1
fi

# Yamayı uygula (önce yedek al)
cp "$CURRENT_FW" "${CURRENT_FW}.backup"
xdelta3 -d -f -s "$CURRENT_FW" /tmp/firmware.xdelta /tmp/firmware_new.bin

# Başarılı mı?
if [ $? -eq 0 ]; then
    mv /tmp/firmware_new.bin "$CURRENT_FW"
    echo "Güncelleme başarılı."
else
    echo "Güncelleme başarısız, yedek geri yükleniyor..."
    cp "${CURRENT_FW}.backup" "$CURRENT_FW"
    exit 1
fi

Delta Yedekleme Sistemi Kurmak

Bu araçların bir diğer güçlü kullanım alanı incremental yedekleme. rsync’in yapamadığı, binary dosyalar içindeki değişiklikleri minimize ederek saklamak:

#!/bin/bash
# delta_backup.sh
# Her gün bir önceki yedeğe göre delta üretir

BACKUP_SOURCE="/var/lib/postgresql/data"
BACKUP_DIR="/backup/postgres"
DATE=$(date +%Y%m%d)
YESTERDAY=$(date -d "yesterday" +%Y%m%d)

CURRENT_SNAPSHOT="$BACKUP_DIR/snapshot_$DATE.tar"
YESTERDAY_SNAPSHOT="$BACKUP_DIR/snapshot_$YESTERDAY.tar"
DELTA_FILE="$BACKUP_DIR/delta_${YESTERDAY}_to_${DATE}.xdelta"

# Günlük tam snapshot al (tar, sıkıştırmasız)
echo "Snapshot oluşturuluyor..."
tar -cf "$CURRENT_SNAPSHOT" -C / var/lib/postgresql/data

# Önceki snapshot varsa delta üret
if [ -f "$YESTERDAY_SNAPSHOT" ]; then
    echo "Delta hesaplanıyor..."
    xdelta3 -e -9 -B 524288000 
        -s "$YESTERDAY_SNAPSHOT" 
        "$CURRENT_SNAPSHOT" 
        "$DELTA_FILE"
    
    echo "Delta boyutu: $(du -sh $DELTA_FILE | cut -f1)"
    echo "Tam snapshot boyutu: $(du -sh $CURRENT_SNAPSHOT | cut -f1)"
    
    # Eski tam snapshot'ı sil (sadece en son tam + deltalar saklanır)
    # Dikkat: Geri yükleme zinciri bozulmasın
    # rm "$YESTERDAY_SNAPSHOT"  # Bu satırı dikkatli kullanın
fi

Delta zincirinden geri yükleme yapmak da ayrıca önemli:

#!/bin/bash
# delta_restore.sh
# Belirli bir tarihe geri yükleme

TARGET_DATE=$1
BASE_SNAPSHOT=$(ls /backup/postgres/snapshot_*.tar | head -1)
BASE_DATE=$(echo "$BASE_SNAPSHOT" | grep -oP 'd{8}')

echo "Taban: $BASE_SNAPSHOT ($BASE_DATE)"
echo "Hedef tarih: $TARGET_DATE"

cp "$BASE_SNAPSHOT" /tmp/restore_working.tar

# Delta'ları sırayla uygula
for DELTA in $(ls /backup/postgres/delta_*.xdelta | sort); do
    DELTA_DATE=$(echo "$DELTA" | grep -oP 'to_Kd{8}')
    
    if [[ "$DELTA_DATE" -le "$TARGET_DATE" ]]; then
        echo "Uygulanan delta: $DELTA"
        xdelta3 -d -f 
            -s /tmp/restore_working.tar 
            "$DELTA" 
            /tmp/restore_working_new.tar
        mv /tmp/restore_working_new.tar /tmp/restore_working.tar
    fi
done

echo "Geri yükleme tamamlandı: /tmp/restore_working.tar"
tar -xf /tmp/restore_working.tar -C /tmp/restore_target/

xdelta3 ve bsdiff Karşılaştırması: Hangisi Ne Zaman?

Teorik karşılaştırmayı bir kenara bırakayım, kendi deneyimlerimden söyleyeyim:

xdelta3 tercih edin:

  • Büyük dosyalar (100MB üzeri), özellikle disk imajları ve büyük veritabanı dump’ları
  • Streaming işlem gerektiğinde (pipe üzerinden doğrudan işleyebilir)
  • Bellek kısıtı varsa (bsdiff’e göre çok daha verimli)
  • Otomatik sıkıştırma isteniyorsa (-9 ile yerleşik)
  • Hız öncelikliyse (bsdiff’ten çok daha hızlı çalışır)

bsdiff tercih edin:

  • Küçük-orta boyutlu executable ve kütüphane dosyaları
  • Yazılım paket güncellemeleri (APT, RPM benzeri sistemler bunu kullanır)
  • Derlenmiş binary’lerde minimal değişiklik varsa
  • Boyut kritikse ve bellek bol ise
# Pratik test: Aynı dosya çifti için her iki araçla karşılaştırma
time xdelta3 -e -9 -s v1.bin v2.bin v1_to_v2.xdelta
time bsdiff v1.bin v2.bin v1_to_v2.bspatch

ls -lh v1_to_v2.xdelta v1_to_v2.bspatch

Çoklu Versiyon Yönetimi

Üretim ortamlarında genellikle birden fazla versiyona yama göndermeniz gerekir. Tüm eski versiyonlardan mevcut versiyona yama zinciri tutmak pratik değil. Bunun için bir ara versiyon (pivot) stratejisi kullanabilirsiniz:

#!/bin/bash
# multi_version_patcher.sh
# Birden fazla eski versiyondan yeni versiyona yama üretir

NEW_VERSION="v3.0.bin"
OLD_VERSIONS=("v2.8.bin" "v2.9.bin" "v2.9.5.bin")

for OLD in "${OLD_VERSIONS[@]}"; do
    OLD_BASE=$(basename "$OLD" .bin)
    NEW_BASE=$(basename "$NEW_VERSION" .bin)
    PATCH_NAME="${OLD_BASE}_to_${NEW_BASE}.xdelta"
    
    echo "Yama üretiliyor: $OLD -> $NEW_VERSION"
    xdelta3 -e -9 -s "$OLD" "$NEW_VERSION" "$PATCH_NAME"
    
    # Boyut raporu
    echo "  Patch boyutu: $(du -sh $PATCH_NAME | cut -f1)"
done

echo "Tüm yamalar oluşturuldu."
ls -lh *.xdelta

Performans İpuçları

Birkaç yıllık kullanımdan edindiğim pratik notlar:

  • Sıkıştırılmış dosyalara dikkat: ZIP, gzip, JPEG gibi zaten sıkıştırılmış dosyaları delta yamalamaya çalışmak verimsizdir. Mümkünse ham veriyi sıkıştırmadan önce deltaları hesaplayın, sonra sıkıştırın.
  • Büyük delta zincirleri sakınca yaratır: 30 günlük delta zinciri tutuyorsanız, geri yükleme süresi katlanarak artar. 7 günde bir tam yedek alın, arasını delta ile doldurun.
  • Paralel işlem: Birden fazla dosya için yamalar oluşturuyorsanız GNU parallel ile hızlandırabilirsiniz.
  • Checksum zorunlu: Delta yamasını uyguladıktan sonra mutlaka SHA256 doğrulaması yapın. Bozuk bir delta, bozuk bir çıktı üretir ve bu bazen sessiz olabilir.
  • -B parametresi büyük dosyalar için kritik: xdelta3’te varsayılan pencere boyutu 8MB. 1GB+ dosyalar için en az 256MB yapın.
# Paralel yama üretimi örneği
ls firmware_*.bin | grep -v v3.0 | 
parallel -j4 "xdelta3 -e -9 -s {} firmware_v3.0.bin {/.}_to_v3.0.xdelta"

Sonuç

xdelta3 ve bsdiff, özellikle bant genişliği veya depolama maliyetinin kritik olduğu ortamlarda gerçekten değer yaratan araçlar. Embedded sistemler, uzak lokasyon güncellemeleri, büyük veri yedekleme senaryoları ve yazılım dağıtım sistemlerinde bu araçları kullanmadan önce ve sonrasını kıyasladığınızda farkı net göreceksiniz.

Ancak birkaç noktanın altını çizmek istiyorum: Delta yama sistemleri, kaynak dosyanın bütünlüğüne bağımlıdır. Kaynak dosya bozuksa veya yanlış versiyonsa, uygulama başarısız olur ya da daha kötüsü sessizce yanlış çıktı üretir. Bu yüzden her adımda checksum doğrulaması yapmak, üretim ortamlarında tartışılmaz bir gereklilik.

xdelta3 genel amaçlı kullanım için daha pratik ve daha az kaynak tüketici. bsdiff ise özellikle executable güncellemelerinde boyut açısından üstün olabilir, ama bellek tüketimi konusunda temkinli olun. İkisini de test ortamınızda deneyin ve hangi senaryoda hangisinin daha iyi sonuç verdiğini kendi verilerinizle ölçün. Genel geçer bir cevap vermek güç; gerçek avantajı ancak kendi dosyalarınızla yaptığınız karşılaştırmada göreceksiniz.

Bir yanıt yazın

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