ZFS Veri Kümelerinde Anlık Görüntü Oluşturma, Geri Yükleme ve Klonlama

ZFS ile çalışmaya başladığımda, snapshot mekanizmasının bu kadar güçlü olduğunu tahmin etmezdim. İlk ciddi veri kaybı senaryomda, yanlış bir rm -rf komutu sonrasında saniyeler içinde sistemi geri getirebildiğimde, bu dosya sistemine olan saygım bambaşka bir boyuta taşındı. Bugün size ZFS snapshot’larının sadece teorisini değil, yıllar içinde edindiğim pratik bilgileri, tuzakları ve gerçek dünya senaryolarını aktaracağım.

ZFS Snapshot Mantığını Anlamak

Snapshot, bir veri kümesinin belirli bir andaki salt okunur kopyasıdır. Ama buradaki kritik nokta şu: ZFS snapshot’ları, anlık görüntü alındığı anda hiç ek disk alanı tüketmez. Copy-on-write (CoW) mekanizması sayesinde yalnızca değişen bloklar için ek alan kullanılır. Yani 100 GB’lık bir dataset’in snapshot’ını aldığınızda, disk üzerinde anlık olarak sıfır byte ek alan harcar.

Bu mekanizmayı anlamak, snapshot yönetiminde doğru kararlar almanızı sağlar. Zamanla değişen veriler büyüdükçe snapshot da büyür. Bir yıl önce aldığınız snapshot, o günden bu yana değişen tüm blokları tuttuğu için beklenenden büyük görünebilir.

ZFS veri hiyerarşisi şöyle çalışır:

  • Pool (havuz): Fiziksel disklerden oluşan depolama havuzu (örn: tank)
  • Dataset: Pool üzerinde oluşturulan dosya sistemi (örn: tank/data)
  • Snapshot: Dataset’in anlık görüntüsü (örn: tank/data@snapshot_adi)
  • Clone: Snapshot’tan türetilen yazılabilir dataset kopyası

Snapshot Oluşturma

Temel syntax son derece sade:

zfs snapshot pool/dataset@snapshot_adi

Gerçek dünyada ise isimlendirme konvansiyonu kritik önem taşır. Tarih ve saat bilgisini otomatik olarak ekleyen bir yapı kullanın:

# Tek bir dataset için anlık görüntü
zfs snapshot tank/production@$(date +%Y%m%d_%H%M%S)

# Örnek çıktı: tank/production@20241215_143022

# Recursive snapshot - tüm alt dataset'leri kapsar
zfs snapshot -r tank/production@$(date +%Y%m%d_%H%M%S)

-r parametresi, tank/production altındaki tüm child dataset’leri tek komutla snapshot’lamanızı sağlar. Büyük ortamlarda bu parametre hayat kurtarır.

Bir web sunucusu senaryosu düşünelim. Nginx konfigürasyon dosyalarınız, uygulama kodunuz ve veritabanı dump’larınız ayrı dataset’lerde tutuluyor:

# Deployment öncesi tüm production dataset'lerinin snapshot'ını al
zfs snapshot -r tank/production@pre_deploy_$(date +%Y%m%d_%H%M%S)

# Snapshot'ların oluştuğunu doğrula
zfs list -t snapshot -r tank/production

Bu komutu her deployment öncesinde çalıştırmak, yanlış giden bir güncelleme sonrasında dakikalar içinde geri dönmenizi sağlar.

Snapshot Listeleme ve Yönetimi

Mevcut snapshot’ları görüntülemek için birkaç farklı yaklaşım var:

# Belirli bir pool'daki tüm snapshot'lar
zfs list -t snapshot

# Yalnızca belirli bir dataset'e ait snapshot'lar
zfs list -t snapshot tank/production

# Boyut bilgisiyle birlikte, insan okunabilir format
zfs list -t snapshot -o name,used,referenced,creation tank/production

# Recursive listeleme, tüm alt dataset snapshot'larını gösterir
zfs list -t snapshot -r tank/production

Çıktıyı analiz ederken dikkat etmeniz gereken iki sütun var: USED ve REFERENCED. REFERENCED sütunu, snapshot alındığı andaki toplam veri boyutunu gösterirken, USED sütunu snapshot’ın o andan bu yana ne kadar ek alan tükettiğini gösterir.

Snapshot sayısı zamanla artınca yönetim zorlaşır. Belirli bir pattern’e göre listelemek için:

# grep ile filtreleme
zfs list -t snapshot | grep "pre_deploy"

# creation zamanına göre sıralı listeleme
zfs list -t snapshot -s creation tank/production

Geri Yükleme (Rollback)

İşte bu noktada ZFS’in gerçek gücü ortaya çıkıyor. Bir dataset’i önceki bir snapshot’a döndürmek:

# Son snapshot'a geri dön
zfs rollback tank/production@20241215_143022

Ancak burada kritik bir davranış var: rollback komutu varsayılan olarak yalnızca en son snapshot’a geri dönmenize izin verir. Daha eski bir snapshot’a dönmek istiyorsanız, o snapshot ile şimdiki zaman arasındaki tüm snapshot’ların silineceğini belirtmeniz gerekir:

# Daha eski bir snapshot'a geri dön, aradaki snapshot'ları sil
zfs rollback -r tank/production@20241214_090000

# -r: snapshot'tan sonraki tüm snapshot'ları da siler
# -R: snapshot'tan türetilmiş clone'ları da siler (dikkatli kullanın)
# -f: aktif mount noktasını zorla unmount edip rollback yapar

Gerçek senaryo: Bir gece yarısı aradım. Ekipten biri yanlış ortamda migration script’ini çalıştırmış, production veritabanı dizinindeki tüm konfigürasyon dosyalarını ezmiş. Snapshot’larımız vardı:

# Önce hangi snapshot'ların mevcut olduğunu kontrol et
zfs list -t snapshot tank/production/config

# Hangi dosyaların değiştiğini snapshot ile karşılaştır
zfs diff tank/production/config@20241215_120000 tank/production/config

# Rollback işlemi
zfs rollback tank/production/config@20241215_120000

# İşlem sonrası doğrulama
ls -la /production/config/

15 dakika içinde sistem tekrar ayaktaydı. Klasik bir backup restore senaryosuyla bu işlem saatler sürebilirdi.

zfs diff komutu, rollback kararı vermeden önce neyin değiştiğini görmenizi sağlar. Bunu bir alışkanlık haline getirin.

Belirli Dosyaları Snapshot’tan Geri Almak

Tüm dataset’i rollback etmek zorunda değilsiniz. ZFS snapshot’ları, mount point’inizde .zfs/snapshot dizini altında erişilebilir durumdadır. Bu dizin çoğu sistemde gizlidir ama erişilebilirdir:

# Snapshot dizinine eriş
ls /production/.zfs/snapshot/

# Belirli bir snapshot'ın içeriğine bak
ls /production/.zfs/snapshot/20241215_143022/

# Tek bir dosyayı snapshot'tan geri al
cp /production/.zfs/snapshot/20241215_143022/app.conf /production/app.conf

# Bir dizini snapshot'tan geri al
cp -r /production/.zfs/snapshot/20241215_143022/configs/ /production/configs/

Bu özellik inanılmaz pratik. Kullanıcılar yanlışlıkla sildikleri dosyayı kendileri bile geri alabilir, sizi geceleri aramak zorunda kalmazlar. Windows’taki “Previous Versions” özelliğinin çok daha güçlü Linux karşılığı olarak düşünebilirsiniz.

Snapshot dizinine erişimi kontrol etmek için:

# snapdir özelliğini göster (hidden veya visible)
zfs get snapdir tank/production

# Kullanıcıların snapshot'larına erişebilmesi için visible yap
zfs set snapdir=visible tank/production

Klonlama (Clone)

Clone, bir snapshot’tan türetilen, tam olarak yazılabilir bir dataset kopyasıdır. Başlangıçta sıfır ek alan kullanır; yalnızca clone üzerinde yapılan değişiklikler disk alanı tüketmeye başlar. Bu özellik, çeşitli senaryolarda müthiş avantajlar sunar.

# Temel clone oluşturma syntax'ı
zfs clone kaynak_snapshot hedef_dataset

# Örnek: production snapshot'ından test ortamı oluştur
zfs snapshot tank/production@clone_base_$(date +%Y%m%d)
zfs clone tank/production@clone_base_20241215 tank/testing

Clone oluşturduktan sonra mount point’i ayarlamanız gerekebilir:

# Clone'u farklı bir dizine mount et
zfs set mountpoint=/opt/testing tank/testing

# Mount durumunu kontrol et
zfs get mountpoint tank/testing
mount | grep tank/testing

Geliştirme Ortamı Senaryosu

En sık kullandığım clone senaryosu, production verisiyle geliştirme ortamı oluşturmak. Yüzlerce GB’lık bir veritabanını kopyalamak saatler alırken, ZFS clone ile saniyeler içinde identik bir geliştirme ortamı elde edebilirsiniz:

#!/bin/bash
# dev_env_refresh.sh - Production'dan güncel dev ortamı oluştur

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
PROD_DATASET="tank/production/database"
SNAP_NAME="${PROD_DATASET}@dev_refresh_${TIMESTAMP}"
DEV_CLONE="tank/development/database"

# Eski dev clone'u temizle (varsa)
if zfs list ${DEV_CLONE} &>/dev/null; then
    echo "Eski development clone siliniyor..."
    zfs destroy ${DEV_CLONE}
fi

# Production'dan snapshot al
echo "Production snapshot alınıyor..."
zfs snapshot ${SNAP_NAME}

# Clone oluştur
echo "Development clone oluşturuluyor..."
zfs clone ${SNAP_NAME} ${DEV_CLONE}

# Geliştirici erişim ayarları
zfs set mountpoint=/opt/dev/database ${DEV_CLONE}

echo "Development ortamı hazır: /opt/dev/database"
echo "Snapshot: ${SNAP_NAME}"

Bu script’i her sabah cron ile çalıştırarak geliştiricilerin her gün taze production verisiyle çalışmasını sağlayabilirsiniz.

Snapshot Silme ve Temizleme

Snapshot’lar zamanla birikerek disk alanı tüketmeye başlar. Düzenli temizlik şart:

# Tek snapshot silme
zfs destroy tank/production@20241201_000000

# Birden fazla snapshot'ı tek seferde sil (ZFS 0.8+)
zfs destroy tank/production@snap1,snap2,snap3

# Range silme - iki snapshot arasındaki tümünü sil
zfs destroy tank/production@20241201_000000%20241210_000000

# Recursive silme - child dataset'lerin aynı isimli snapshot'larını da sil
zfs destroy -r tank/production@20241201_000000

Dikkat: Bir snapshot’ı silmeden önce üzerinden clone türetilip türetilmediğini kontrol edin. Clone’un bağlı olduğu snapshot silinmeden önce clone’un ya silinmesi ya da promote edilmesi gerekir.

# Snapshot'a bağlı clone'ları kontrol et
zfs get clones tank/production@20241215_143022

Otomatik temizleme için basit bir script:

#!/bin/bash
# snapshot_cleanup.sh - 30 günden eski snapshot'ları temizle

DATASET="tank/production"
KEEP_DAYS=30

echo "30 günden eski snapshot'lar temizleniyor..."

zfs list -t snapshot -o name,creation -p ${DATASET} | 
    awk -v cutoff="$(date -d "${KEEP_DAYS} days ago" +%s)" 
    '$2 < cutoff {print $1}' | 
    while read snap; do
        echo "Siliniyor: $snap"
        zfs destroy "$snap"
    done

echo "Temizleme tamamlandı."

Clone Promote Etmek

Bu kavram başlangıçta biraz kafa karıştırıcı gelebilir ama son derece önemli. Normalde bir clone, türetildiği snapshot’a bağımlıdır; o snapshot silinemez. Ancak zfs promote komutu ile bu bağımlılık tersine çevrilebilir.

# Clone'u bağımsız hale getir
zfs promote tank/testing

# Artık orijinal dataset clone haline gelir
# tank/testing artık bağımsız bir dataset'tir
# tank/production ise artık tank/testing'in clone'udur

Bu işlemi şu senaryoda kullanırsınız: Test ortamında kapsamlı bir refactoring yaptınız, her şey mükemmel çalışıyor ve test’i production’a terfi ettirmek istiyorsunuz. Veri kopyalamak yerine promote edip mount point’leri değiştirirsiniz. Sıfır downtime, sıfır veri kopyalama.

Otomatik Snapshot için Pratik Yaklaşımlar

Elle snapshot almak unutmaya açık bir süreç. Bunu otomatize etmenin birkaç yolu var:

Cron tabanlı basit yaklaşım:

# /etc/cron.d/zfs-snapshots dosyası

# Her saat başı snapshot
0 * * * * root /usr/local/bin/zfs-auto-snapshot.sh hourly 24

# Günlük snapshot (gece yarısı)
0 0 * * * root /usr/local/bin/zfs-auto-snapshot.sh daily 30

# Haftalık snapshot (Pazar gece yarısı)
0 0 * * 0 root /usr/local/bin/zfs-auto-snapshot.sh weekly 8

Daha kapsamlı bir çözüm için zfs-auto-snapshot paketi mevcuttur:

# Debian/Ubuntu sistemlerde
apt install zfs-auto-snapshot

# Hangi dataset'lerde aktif olduğunu kontrol et
zfs get com.sun:auto-snapshot tank/production

# Belirli bir dataset için aktif et
zfs set com.sun:auto-snapshot=true tank/production

# Belirli bir snapshot sıklığı için kapat
zfs set com.sun:auto-snapshot:hourly=false tank/production/logs

Snapshot’ları Farklı Bir Havuza veya Sunucuya Transfer Etmek

ZFS’in bir diğer güçlü özelliği, snapshot’ları stream formatında başka sistemlere göndermektir. Bu, hem yedekleme hem de migration için kullanılır:

# Snapshot'ı dosyaya kaydet (yedekleme)
zfs send tank/production@20241215_143022 | gzip > /backup/production_20241215.zfs.gz

# Dosyadan geri yükle
gunzip -c /backup/production_20241215.zfs.gz | zfs receive tank/production_restore

# Snapshot'ı SSH üzerinden remote sunucuya gönder
zfs send tank/production@20241215_143022 | 
    ssh backup-server "zfs receive backup_pool/production"

# Incremental send - yalnızca iki snapshot arasındaki değişiklikleri gönder
zfs send -i tank/production@20241214_000000 tank/production@20241215_000000 | 
    ssh backup-server "zfs receive backup_pool/production"

Incremental send, bant genişliği açısından son derece verimlidir. Günde bir kez full send yerine, saatlik incremental’lar ile çok daha az veri transfer edebilirsiniz.

Yaygın Hatalar ve Dikkat Edilmesi Gerekenler

Yıllar içinde hem kendim yaptım hem de başkalarının yaptığını gördüm:

  • Snapshot isimlerinde boşluk kullanmak: ZFS izin verir ama komut satırında kaçış karakteri gerektireceği için kaçının. Alt çizgi ve tire kullanın.
  • Clone’dan sonra orijinal snapshot’ı silmeye çalışmak: zfs destroy hata verir. Önce clone’u silin ya da promote edin.
  • Rollback sırasında aktif bağlantıları dikkate almamak: Veritabanı gibi servisler dosyaları açık tutabilir. Rollback öncesi servisi durdurun.
  • Çok fazla snapshot biriktirmek: Her snapshot, referans aldığı blokları tutar. Disk doluluk hesaplarken bunu göz önünde bulundurun. zfs list -t all -o space ile detaylı alan kullanımını inceleyin.
  • Recursive snapshot alırken child dataset sayısını gözden kaçırmak: -r ile alınan snapshot’lar beklenenden fazla yer kaplayabilir.
# Tüm dataset'lerin alan kullanımını detaylı görüntüle
zfs list -t all -o name,used,available,referenced,usedbysnapshots

usedbysnapshots sütunu, snapshot’ların ne kadar alan tükettiğini gösterir. Bu değer büyümeye başlarsa temizleme vakti gelmiş demektir.

Sonuç

ZFS snapshot mekanizması, doğru anlaşılıp doğru kullanıldığında geleneksel yedekleme yaklaşımlarını birçok senaryoda geride bırakır. Anlık geri dönüş kapasitesi, sıfır maliyetli geliştirme ortamı klonlama ve verimli incremental transfer özellikleri, özellikle veri yoğun ortamlarda ciddi operasyonel avantajlar sunar.

Ancak şunu da netleştirmek gerekir: Snapshot, yedeklemenin yerini tutmaz. Aynı pool üzerinde tutulan snapshot’lar, disk arızasına karşı sizi korumaz. Snapshot’larınızı zfs send ile farklı fiziksel konumlara aktarmanız gerçek anlamda bir felaketten kurtarma stratejisi oluşturur.

Bugün başlamak için basit bir adım: Production dataset’lerinize günlük otomatik snapshot ekleyin, .zfs/snapshot dizinini visible yapın ve ekibinize bu dizinden kendi dosyalarını nasıl geri alacaklarını öğretin. Bu tek değişiklik bile “yanlışlıkla sildim” aramalarını önemli ölçüde azaltacaktır.

Bir yanıt yazın

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