Btrfs Anlık Görüntüleri ile Dosya Sistemi Yedekleme ve Geri Yükleme: send/receive Kullanımı

Yıllarca farklı yedekleme çözümleriyle boğuştuktan sonra şunu söyleyebilirim: btrfs’in send/receive mekanizması, dosya sistemi düzeyinde yedekleme konusunda ciddi bir oyun değiştirici. Özellikle büyük veri setlerini yönetirken, anlık görüntü tabanlı artımlı yedeklemelerin getirdiği verimlilik başka hiçbir yaklaşımla kıyaslanamıyor. Bu yazıda teorik anlatımdan çok, gerçek dünyada işe yarayan pratik bir yaklaşım sunmaya çalışacağım.

btrfs Anlık Görüntüleri Nedir ve Neden Önemlidir?

btrfs, copy-on-write (COW) mimarisi üzerine inşa edilmiş bir dosya sistemidir. Bu mimari sayesinde anlık görüntüler (snapshot), veriyi fiziksel olarak kopyalamak yerine mevcut veri bloklarına referans oluşturarak çalışır. Pratik sonucu: bir anlık görüntü almak neredeyse anlıktır ve başlangıçta disk üzerinde ek alan kaplamaz.

Ancak asıl güç btrfs send ve btrfs receive komutlarında gizlidir. Bu komutlar sayesinde:

  • Bir dosya sisteminin anlık görüntüsünü başka bir diske veya uzak sunucuya aktarabilirsiniz
  • İki anlık görüntü arasındaki farkı (delta) hesaplayıp sadece değişen blokları gönderebilirsiniz
  • Yedekleme işlemini tamamen dosya sistemi düzeyinde, uygulama katmanından bağımsız olarak gerçekleştirebilirsiniz

Bu özellik, özellikle büyük veritabanı sunucularında, sanal makine disk görüntülerinde ve medya arşivlerinde ciddi bir avantaj sağlar.

Ön Koşullar ve Ortam Hazırlığı

Önce elimizin altında ne olması gerektiğine bakalım. Örneklerde /dev/sdb kaynak disk, /dev/sdc ise yedekleme diski olarak kullanılıyor.

# btrfs-progs paketini yükleyin
sudo apt install btrfs-progs          # Debian/Ubuntu
sudo dnf install btrfs-progs          # Fedora/RHEL
sudo pacman -S btrfs-progs            # Arch Linux

# btrfs araçlarının sürümünü doğrulayın
btrfs --version

# Diskleri btrfs olarak biçimlendirin
sudo mkfs.btrfs /dev/sdb
sudo mkfs.btrfs /dev/sdc

# Bağlama noktalarını oluşturun
sudo mkdir -p /mnt/source /mnt/backup

# Diskleri bağlayın
sudo mount /dev/sdb /mnt/source
sudo mount /dev/sdc /mnt/backup

Burada dikkat edilmesi gereken önemli bir nokta var: send/receive işlemi için anlık görüntünün salt okunur (read-only) olması zorunludur. Yazılabilir anlık görüntülerden send komutu çalıştırmaya çalışırsanız hata alırsınız. Bu, btrfs’in tutarlılık garantisi için koyduğu bir kısıtlama.

Alt Birim (Subvolume) Yapısını Kurma

btrfs’de anlık görüntüler subvolume’lar üzerinden çalışır. Önce kaynak verilerimiz için bir subvolume oluşturalım:

# Kaynak için bir subvolume oluştur
sudo btrfs subvolume create /mnt/source/data

# İçine örnek veri koyalım
sudo cp -r /etc /mnt/source/data/
sudo dd if=/dev/urandom of=/mnt/source/data/test_file.bin bs=1M count=100

# Subvolume listesini kontrol et
sudo btrfs subvolume list /mnt/source

Gerçek ortamlarda genellikle şu yapıyı kullanırım: ana disk @ subvolume’una kök dosya sistemi için, @home subvolume’una ise kullanıcı dizinleri için bağlıdır. Bu sayede her iki bölümü bağımsız olarak yedekleyip geri yükleyebilirsiniz.

İlk Tam Yedekleme: send/receive Temelleri

Anlık görüntü alıp onu yedekleme diskine gönderme işlemi birkaç adımdan oluşur:

# Salt okunur anlık görüntü al
sudo btrfs subvolume snapshot -r /mnt/source/data /mnt/source/snapshots/data_2024-01-15

# Snapshot'ın bilgilerini doğrula
sudo btrfs subvolume show /mnt/source/snapshots/data_2024-01-15

# Yedekleme diskinde hedef dizini oluştur
sudo mkdir -p /mnt/backup/snapshots

# send/receive ile tam yedekleme başlat
sudo btrfs send /mnt/source/snapshots/data_2024-01-15 | 
  sudo btrfs receive /mnt/backup/snapshots/

btrfs send komutu veriyi bir stream olarak stdout’a yazar, btrfs receive ise bu stream’i alıp hedef btrfs dosya sistemine uygular. Pipe kullanımı bu iki komutu doğrudan birbirine bağlar.

İlk tam yedekleme büyük veri setlerinde uzun sürebilir. İlerlemeyi takip etmek için pv aracından yararlanabilirsiniz:

# pv ile ilerleme takibi
sudo btrfs send /mnt/source/snapshots/data_2024-01-15 | 
  pv | 
  sudo btrfs receive /mnt/backup/snapshots/

Artımlı Yedekleme: Gerçek Güç Burada

İlk tam yedeklemeden sonra veriyi değiştirip ikinci bir anlık görüntü alalım:

# Veriye değişiklikler yap
sudo touch /mnt/source/data/new_file.txt
sudo rm /mnt/source/data/test_file.bin
sudo cp /var/log/syslog /mnt/source/data/

# İkinci anlık görüntü al
sudo btrfs subvolume snapshot -r /mnt/source/data /mnt/source/snapshots/data_2024-01-16

# Artımlı yedekleme: sadece iki snapshot arasındaki farkı gönder
sudo btrfs send 
  -p /mnt/source/snapshots/data_2024-01-15 
  /mnt/source/snapshots/data_2024-01-16 | 
  sudo btrfs receive /mnt/backup/snapshots/

-p parametresi parent snapshot‘ı belirtir. btrfs bu iki snapshot arasındaki farkı hesaplar ve sadece değişen blokları aktarır. 100 GB’lık bir veri setinde sadece birkaç MB değişiklik varsa, sadece o birkaç MB transfer edilir. Bu, özellikle sınırlı bant genişliğiyle uzak yedekleme yapanlar için büyük bir avantaj.

Uzak Sunucuya SSH Üzerinden Yedekleme

Çoğu zaman yedekleme aynı makinede değil, uzak bir sunucuda tutulur. btrfs send ve btrfs receive SSH ile mükemmel çalışır:

# Uzak sunucuya ilk tam yedekleme
sudo btrfs send /mnt/source/snapshots/data_2024-01-15 | 
  ssh backup-server "sudo btrfs receive /mnt/remote-backup/snapshots/"

# Uzak sunucuya artımlı yedekleme
sudo btrfs send 
  -p /mnt/source/snapshots/data_2024-01-15 
  /mnt/source/snapshots/data_2024-01-16 | 
  ssh backup-server "sudo btrfs receive /mnt/remote-backup/snapshots/"

SSH üzerinden gönderirken sıkıştırma eklemek de mantıklı olabilir. Ağ darboğazı yaşayan ortamlarda lz4 veya zstd ile sıkıştırma, toplam transfer süresini önemli ölçüde düşürür:

# lz4 sıkıştırmayla uzak yedekleme
sudo btrfs send /mnt/source/snapshots/data_2024-01-16 | 
  lz4 | 
  ssh backup-server "lz4 -d | sudo btrfs receive /mnt/remote-backup/snapshots/"

Burada bir not düşeyim: uzak sunucudaki btrfs receive komutunu sudo ile çalıştırmak için ya /etc/sudoers dosyasına uygun bir kural ekleyin, ya da yedekleme işlemleri için ayrı bir kullanıcı ve btrfs yeteneklerine sahip özel bir yapı kurun. Root ile SSH bağlantısına izin vermek, pratikte kaçınmanız gereken bir yaklaşım.

Geri Yükleme İşlemi

Bir felaketten sonra veya yanlışlıkla silinen dosyaları geri getirmek için snapshot’ları nasıl kullanacağımıza bakalım.

Belirli bir dosyayı geri yüklemek:

# Backup'taki snapshot'ı geçici olarak bağla
sudo btrfs subvolume snapshot 
  /mnt/backup/snapshots/data_2024-01-15 
  /mnt/backup/restore_temp

# Gerekli dosyayı kopyala
sudo cp /mnt/backup/restore_temp/önemli_dosya.txt /mnt/source/data/

# Geçici snapshot'ı sil
sudo btrfs subvolume delete /mnt/backup/restore_temp

Tüm subvolume’u belirli bir noktaya geri döndürmek:

# Mevcut subvolume'u yedekle (ihtiyatlı olalım)
sudo btrfs subvolume snapshot -r /mnt/source/data /mnt/source/snapshots/data_before_restore

# Mevcut subvolume'u sil
sudo btrfs subvolume delete /mnt/source/data

# Backup'tan seçilen snapshot'ı geri yükle
sudo btrfs send /mnt/backup/snapshots/data_2024-01-15 | 
  sudo btrfs receive /mnt/source/

# Salt okunur snapshot'tan yazılabilir subvolume oluştur
sudo btrfs subvolume snapshot 
  /mnt/source/data_2024-01-15 
  /mnt/source/data

# Artık geçici salt okunur kopyayı kaldırabilirsiniz
sudo btrfs subvolume delete /mnt/source/data_2024-01-15

Bu noktada dikkat edilmesi gereken ince bir detay var: btrfs receive ile gelen snapshot salt okunurdur. Doğrudan üzerinde çalışmak yerine, ondan yazılabilir bir snapshot oluşturmanız gerekir.

Snapshot Yönetimi ve Otomatik Temizlik

Zamanla snapshot’lar birikir ve disk dolmaya başlar. Otomatik bir temizlik mekanizması kurmak şart:

#!/bin/bash
# /usr/local/bin/btrfs-backup.sh

SOURCE_SUBVOL="/mnt/source/data"
SNAPSHOT_DIR="/mnt/source/snapshots"
BACKUP_DIR="/mnt/backup/snapshots"
DATE=$(date +%Y-%m-%d_%H-%M)
KEEP_DAYS=7

# Yeni snapshot al
SNAPSHOT_NAME="data_${DATE}"
btrfs subvolume snapshot -r "${SOURCE_SUBVOL}" "${SNAPSHOT_DIR}/${SNAPSHOT_NAME}"

# En son önceki snapshot'ı bul (artımlı yedekleme için parent)
PREV_SNAPSHOT=$(ls -1t "${SNAPSHOT_DIR}" | grep -v "${SNAPSHOT_NAME}" | head -1)

if [ -z "${PREV_SNAPSHOT}" ]; then
    # İlk yedekleme, tam gönderim
    btrfs send "${SNAPSHOT_DIR}/${SNAPSHOT_NAME}" | 
        btrfs receive "${BACKUP_DIR}/"
else
    # Artımlı gönderim
    btrfs send 
        -p "${SNAPSHOT_DIR}/${PREV_SNAPSHOT}" 
        "${SNAPSHOT_DIR}/${SNAPSHOT_NAME}" | 
        btrfs receive "${BACKUP_DIR}/"
fi

# Eski snapshot'ları temizle (KEEP_DAYS günden eski olanlar)
find "${SNAPSHOT_DIR}" -maxdepth 1 -type d -name "data_*" 
    -mtime "+${KEEP_DAYS}" | while read old_snapshot; do
    btrfs subvolume delete "${old_snapshot}"
done

echo "Yedekleme tamamlandı: ${SNAPSHOT_NAME}"

Bu betiği crontab’a ekleyin:

# Her gün gece 02:00'de çalıştır
0 2 * * * /usr/local/bin/btrfs-backup.sh >> /var/log/btrfs-backup.log 2>&1

Veri Bütünlüğü Doğrulama

Yedekleme yaptınız güzel, ama geri yükleyebiliyor musunuz? Bu soruyu sormadan geçmeyin. btrfs’in yerleşik checksum mekanizması bu konuda yardımcı olur:

# Dosya sistemi tutarlılığını kontrol et
sudo btrfs scrub start /mnt/backup
sudo btrfs scrub status /mnt/backup

# Snapshot'ların listesini ve boyutlarını görüntüle
sudo btrfs subvolume list -s /mnt/backup

# Disk kullanımını incele
sudo btrfs filesystem usage /mnt/backup

# Belirli bir snapshot'ın boyutunu öğren
sudo btrfs qgroup show /mnt/backup

Scrub işlemi arka planda çalışır ve tüm veri bloklarını okuyarak checksum’ları doğrular. Bozuk bloklara rastlarsa sistem loguna yazar. Bunu da crontab ile haftalık çalıştırmak iyi bir alışkanlık.

Gerçek Dünya Senaryosu: PostgreSQL Sunucusu Yedekleme

Şimdi daha somut bir senaryoya geçelim. PostgreSQL veri dizini btrfs üzerinde olan bir sunucuyu düşünün. Dosya sistemi düzeyinde tutarlı bir yedekleme almak için şu yaklaşımı kullanabilirsiniz:

#!/bin/bash
# PostgreSQL + btrfs snapshot yedekleme

PG_DATA="/mnt/pgdata/postgresql"
SNAPSHOT_DIR="/mnt/pgdata/snapshots"
BACKUP_HOST="backup-server"
BACKUP_DIR="/mnt/remote-backup/pg-snapshots"
DATE=$(date +%Y-%m-%d_%H-%M)

# PostgreSQL'e checkpoint yaptır (tampon verileri diske flush et)
sudo -u postgres psql -c "CHECKPOINT;"

# Salt okunur snapshot al
SNAP="${SNAPSHOT_DIR}/pg_${DATE}"
sudo btrfs subvolume snapshot -r "${PG_DATA}" "${SNAP}"

# Checkpoint tamamlandığı için artık IO normal devam edebilir
# Snapshot alındıktan sonra PostgreSQL'in çalışmasını engellemiyoruz

# Önceki snapshot adını bul
PREV_SNAP=$(ls -1t "${SNAPSHOT_DIR}" | grep -v "pg_${DATE}" | head -1)

if [ -n "${PREV_SNAP}" ]; then
    sudo btrfs send 
        -p "${SNAPSHOT_DIR}/${PREV_SNAP}" 
        "${SNAP}" | 
        ssh "${BACKUP_HOST}" "sudo btrfs receive ${BACKUP_DIR}/"
else
    sudo btrfs send "${SNAP}" | 
        ssh "${BACKUP_HOST}" "sudo btrfs receive ${BACKUP_DIR}/"
fi

Bu yaklaşım klasik pg_dump ile karşılaştırıldığında çok daha hızlıdır çünkü PostgreSQL’i durdurmak gerekmez ve yedekleme süresi veri miktarından bağımsız olarak çok kısadır. Ancak şunu belirtmek gerekir: bu yedekten geri yükleme yaparken PostgreSQL’in recovery mekanizmasının devreye girmesi gerekebilir, bu nedenle WAL arşivlemeyle birlikte kullanmak en sağlam yaklaşımdır.

Sık Karşılaşılan Sorunlar ve Çözümleri

“ERROR: could not find parent subvolume” hatası:

Bu hata, artımlı yedekleme yaparken parent snapshot yedek tarafında bulunamazsa ortaya çıkar. Çözüm: parent snapshot’ın hem kaynak hem hedef tarafta mevcut olduğundan emin olun. Parent’ı silerken dikkatli olun.

Salt okunur snapshot’tan “Operation not permitted” hatası:

# Yazılabilir kopya oluşturun
sudo btrfs subvolume snapshot 
  /mnt/backup/snapshots/data_readonly 
  /mnt/working/data_writable

Disk doluluk sorunu:

btrfs bazen df çıktısını yanıltıcı gösterir. Gerçek durumu görmek için:

sudo btrfs filesystem df /mnt/backup
sudo btrfs filesystem usage /mnt/backup

send işleminin yarıda kesilmesi:

Uzun transfer süreçlerinde bağlantı kopabilir. Bu durumda hedef taraftaki yarım kalan subvolume’u silip baştan başlamak en güvenli yoldur:

# Yarım kalan snapshot'ı sil
sudo btrfs subvolume delete /mnt/backup/snapshots/data_incomplete

send/receive Komutlarının Temel Parametreleri

btrfs send parametreleri:

  • -p : Artımlı gönderim için parent snapshot belirtir
  • -c : Birden fazla parent kullanarak daha verimli delta hesaplar
  • -e: Her subvolume’u ayrı bir stream segmenti olarak gönderir
  • -q: Sessiz mod, sadece hataları gösterir
  • –no-data: Sadece metadata gönderir, veri transferi yapmaz (test için kullanışlı)

btrfs receive parametreleri:

  • -e: Stream içindeki her segmenti ayrı ayrı işler
  • -C: Checksum doğrulamayı atlar (performans için, tavsiye edilmez)
  • -q: Sessiz mod
  • –dump: Veriyi uygulamak yerine stream içeriğini gösterir (hata ayıklama için)

Sonuç

btrfs send/receive mekanizması, doğru kurulduğunda inanılmaz verimli bir yedekleme altyapısı sağlar. Artımlı yedeklemeler sayesinde hem depolama alanından hem de transfer süresinden ciddi tasarruf elde edersiniz. Özellikle değişim oranı düşük büyük veri setlerinde bu yaklaşımın geleneksel rsync tabanlı yedeklemelerle karşılaştırması neredeyse komik bir hal alıyor; rsync her seferinde dosyaları taramak zorundayken btrfs tam olarak neyin değiştiğini zaten biliyor.

Ancak şunu da açıkça söyleyelim: btrfs hala olgun bir dosya sistemi olmaya devam etse de production ortamlarda btrfs kullanmadan önce kendi test senaryolarınızı çalıştırın. RAID 5/6 modları hala deneysel kabul edilir. Yedekleme stratejinizi sadece btrfs snapshot’larına bağlamayın; klasik yedekleme araçlarıyla kombine eden katmanlı bir yaklaşım her zaman daha sağlıklıdır.

Son olarak: yedekleme test etmeden anlamını yitirir. Yukarıdaki geri yükleme adımlarını en az üç ayda bir gerçek verilerle test edin. Felaket anında “acaba çalışır mı?” sorusunu sormak istemezsiniz.

Bir yanıt yazın

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