LVM Snapshot ile Hızlı Yedekleme Alma

Üretim sunucusunda yedek almak zorunda kaldığınızda, sistemi durdurmadan tutarlı bir kopya elde etmek her zaman baş ağrısı olmuştur. LVM snapshot tam da bu noktada devreye giriyor: çalışan bir sistemi kesmeden, anlık bir disk görüntüsü alıyorsunuz ve bu görüntü üzerinden rahatça yedekleme yapabiliyorsunuz. Bugün LVM snapshot mekanizmasını baştan sona ele alacağız; teori kısmını minimumda tutup asıl odağı gerçek dünya senaryolarına vereceğiz.

LVM Snapshot Nedir ve Nasıl Çalışır?

LVM (Logical Volume Manager) snapshot’ı anlamak için önce “Copy-on-Write” (CoW) mekanizmasını bilmek gerekiyor. Snapshot aldığınızda LVM, orijinal volume’ün o anki halinin bir haritasını çıkarır. Yeni veri yazılmak istendiğinde, LVM önce eski veriyi snapshot alanına kopyalar, sonra yeni veriyi orijinal konuma yazar. Bu sayede snapshot her zaman alındığı andaki tutarlı görüntüyü korur.

Bu yaklaşımın en güzel yanı şu: snapshot aldığınız anda sistemin dondurulmasına gerek yok. Veritabanı çalışmaya devam ediyor, web sunucusu istek almaya devam ediyor, kullanıcılar bir şeyin farkında bile olmuyor.

Ancak şunu net söylemek gerekiyor: snapshot, yedek değil yedek almanın bir aracıdır. Snapshot’ı aldıktan sonra onu bir yere kopyalamanız ya da bir yedekleme aracına beslemeniz gerekiyor. Bunu karıştıran sistem yöneticilerini çok gördüm, disk dolunca her şey mahvoldu.

Ön Gereksinimler ve Mevcut Durumu Kontrol Etme

Başlamadan önce sisteminizin durumuna bakalım. LVM kurulu mu, volume group’ta yeterli boş alan var mı?

# LVM kurulu mu kontrol et
which lvm
lvmconfig --version

# Mevcut volume group'lara bak
vgs

# Detaylı volume group bilgisi
vgdisplay

# Logical volume'leri listele
lvs

# Daha detaylı bilgi
lvdisplay

vgs komutunun çıktısında VFree sütununa dikkat edin. Bu alan snapshot için kullanacağınız boş alanı gösteriyor. Eğer bu alan sıfır ya da çok azsa, snapshot oluşturmadan önce ya yeni disk ekleyip VG’ye dahil etmeniz ya da mevcut kullanımı gözden geçirmeniz gerekiyor.

Tipik bir çıktı şöyle görünür:

VG        #PV #LV #SN Attr   VSize   VFree
vg_data     1   3   0 wz--n- 500.00g 120.00g

120.00g boş alan var, bu iyi. Snapshot için yeterli.

İlk Snapshot’ı Oluşturma

Şimdi asıl işe girelim. Diyelim ki /dev/vg_data/lv_production adında bir logical volume’ünüz var ve bunu yedeklemek istiyorsunuz.

# Snapshot oluştur
lvcreate -L 20G -s -n lv_production_snap /dev/vg_data/lv_production

# Oluşturulan snapshot'ı doğrula
lvs -a | grep snap

# Snapshot detaylarına bak
lvdisplay /dev/vg_data/lv_production_snap

Buradaki parametreleri açıklayayım:

-L 20G: Snapshot için ayrılacak alan. Orijinal volume’ün tamamı değil, değişikliklerin yazılacağı CoW alanı bu. Ne kadar vereceğinizi aşağıda konuşacağız.

-s: Bu bir snapshot olduğunu belirtir.

-n lv_production_snap: Snapshot’a verilen isim. Tarih eklemek iyi bir alışkanlıktır: lv_production_snap_20240115 gibi.

-p r: İsteğe bağlı, snapshot’ı salt okunur yapar. Yedekleme amaçlıysa bunu eklemenizi öneririm.

Snapshot boyutunu belirlemek başlı başına bir konu. Genel kural şu: ne kadar veri değişeceğini tahmin edin ve ona göre yer ayırın. Yedekleme işlemi 2 saat sürecekse ve sisteminiz saatte 5 GB veri yazıyorsa, en az 10-15 GB snapshot alanı gerekiyor. Snapshot dolduğunda LVM onu geçersiz olarak işaretler ve hem snapshot hem orijinal volume erişilemez hale gelebilir. Bu duruma düşmeyin.

Snapshot’ı Mount Edip İçeriği Kontrol Etme

# Mount noktası oluştur
mkdir -p /mnt/backup_snap

# Snapshot'ı mount et (salt okunur)
mount -o ro /dev/vg_data/lv_production_snap /mnt/backup_snap

# İçeriği doğrula
ls -la /mnt/backup_snap/
df -h /mnt/backup_snap

# Snapshot kullanım oranını izle
lvs -a /dev/vg_data/lv_production_snap

lvs çıktısındaki Data% sütunu kritik. Bu sütun snapshot alanının yüzde kaçının dolduğunu gösteriyor. %80’i aşmaya başlarsa alarm verin, hemen yedekleme sürecini hızlandırın ya da snapshot boyutunu genişletin.

Snapshot boyutunu sonradan genişletmek mümkün:

# Snapshot boyutunu 10 GB artır
lvextend -L +10G /dev/vg_data/lv_production_snap

Gerçek Dünya Senaryosu 1: rsync ile Dosya Sistemi Yedeklemesi

En yaygın kullanım senaryosu bu. Snapshot alıp rsync ile uzak sunucuya kopyalıyorsunuz.

#!/bin/bash
# /usr/local/bin/lvm_backup.sh

set -euo pipefail

# Değişkenler
VG="vg_data"
LV="lv_production"
SNAP_NAME="${LV}_snap_$(date +%Y%m%d_%H%M%S)"
SNAP_SIZE="25G"
MOUNT_POINT="/mnt/backup_snap"
REMOTE_HOST="backup-server.example.com"
REMOTE_PATH="/backups/production"
LOG_FILE="/var/log/lvm_backup.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

cleanup() {
    log "Temizlik yapılıyor..."
    umount "$MOUNT_POINT" 2>/dev/null || true
    lvremove -f "/dev/${VG}/${SNAP_NAME}" 2>/dev/null || true
    log "Temizlik tamamlandı"
}

# Hata durumunda cleanup çalışsın
trap cleanup EXIT

log "Yedekleme başlatılıyor: $SNAP_NAME"

# Snapshot oluştur
lvcreate -L "$SNAP_SIZE" -s -n "$SNAP_NAME" -p r "/dev/${VG}/${LV}"
log "Snapshot oluşturuldu: $SNAP_NAME"

# Mount et
mkdir -p "$MOUNT_POINT"
mount -o ro,noatime "/dev/${VG}/${SNAP_NAME}" "$MOUNT_POINT"
log "Snapshot mount edildi: $MOUNT_POINT"

# rsync ile uzak sunucuya aktar
rsync -avz --delete 
    --exclude="*.tmp" 
    --exclude="*.log" 
    --log-file="$LOG_FILE" 
    "$MOUNT_POINT/" 
    "${REMOTE_HOST}:${REMOTE_PATH}/"

log "rsync tamamlandı"

# cleanup trap otomatik çalışacak
log "Yedekleme başarıyla tamamlandı"

Bu scriptte trap cleanup EXIT satırına dikkat edin. Script herhangi bir nedenle yarıda kesilse bile, snapshot temizlenecek ve mount noktası bırakılmayacak. Üretim ortamında bu tür güvenli kapanış mekanizmaları hayat kurtarıyor.

Gerçek Dünya Senaryosu 2: Veritabanı Yedeklemesi

Veritabanı yedeklemesi biraz daha dikkat istiyor. Dosya sistemi tutarlılığı yeterli değil, veritabanının kendi tutarlılık durumunu da yönetmek gerekiyor.

MySQL/MariaDB için önce flush ve lock, sonra snapshot:

#!/bin/bash
# MySQL için LVM snapshot yedekleme

MYSQL_USER="backup_user"
MYSQL_PASS="guclu_bir_sifre"
VG="vg_mysql"
LV="lv_mysql_data"
SNAP_SIZE="15G"
SNAP_NAME="mysql_snap_$(date +%Y%m%d_%H%M)"
MOUNT_POINT="/mnt/mysql_snap"

# MySQL'i kilitle (çok kısa süreli)
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -e "FLUSH TABLES WITH READ LOCK; SYSTEM lvcreate -L ${SNAP_SIZE} -s -n ${SNAP_NAME} /dev/${VG}/${LV}; UNLOCK TABLES;"

# Snapshot'ı mount et
mkdir -p "$MOUNT_POINT"
mount -o ro "/dev/${VG}/${SNAP_NAME}" "$MOUNT_POINT"

# xtrabackup ya da rsync ile yedekle
rsync -avz "$MOUNT_POINT/" backup-server:/backups/mysql/

# Temizlik
umount "$MOUNT_POINT"
lvremove -f "/dev/${VG}/${SNAP_NAME}"

Aslında MySQL için Percona XtraBackup kullanıyorsanız, o kendi içinde bu kilitleme mekanizmasını yönetiyor. Ama temel mantığı anlamak için bu yaklaşımı bilmek önemli.

PostgreSQL tarafında ise pg_start_backup() ve pg_stop_backup() fonksiyonlarıyla checkpoint yönetimi yapmanız gerekiyor. Bu konu ayrı bir yazı konusu ama temel yapı aynı: veritabanına bildir, snapshot al, veritabanına bittiğini söyle, yedeklemeyi yap.

Snapshot Boyutu Hesaplama ve İzleme

Bu konuya biraz daha eğilmek istiyorum çünkü en çok sorun burada çıkıyor. Snapshot boyutunu küçük tutarsanız dolar, büyük tutarsanız disk israfı olur.

# Sistemin yazma hızını izle (iostat gerekli)
iostat -x 1 10 | grep -E "(Device|sda|sdb|dm-)"

# LVM ile yazma istatistikleri
dmstats create /dev/vg_data/lv_production
dmstats report /dev/vg_data/lv_production

# Snapshot doluluk oranını gerçek zamanlı izle
watch -n 5 'lvs -a --units g /dev/vg_data/lv_production_snap'

Pratik hesaplama için şu formülü kullanıyorum: Snapshot Boyutu = (Saatlik Yazma Hızı Yedekleme Süresi 1.5) + Güvenlik Marjı

Örneğin sistemin saatte 8 GB yazma yaptığı ve yedeklemenin 3 saat sürdüğünü biliyorsanız: 8 3 1.5 = 36 GB snapshot alanı mantıklı bir başlangıç noktası.

Otomatik Snapshot Yönetimi

Elle snapshot alıp silmek hata yaratır. Cron ile otomatize etmek ve eski snapshot’ları temizlemek şart.

# /usr/local/bin/snapshot_cleanup.sh
#!/bin/bash

# 24 saatten eski snapshot'ları temizle
VG="vg_data"
MAX_AGE_HOURS=24

# Snapshot listesini al
lvs --noheadings -o lv_name "$VG" | grep "_snap_" | while read snap_name; do
    # Snapshot oluşturma zamanını al
    snap_time=$(lvs --noheadings -o lv_time "${VG}/${snap_name}" 2>/dev/null | tr -d ' ')
    
    if [ -n "$snap_time" ]; then
        # Yaş hesapla
        snap_epoch=$(date -d "$snap_time" +%s 2>/dev/null || echo 0)
        current_epoch=$(date +%s)
        age_hours=$(( (current_epoch - snap_epoch) / 3600 ))
        
        if [ "$age_hours" -gt "$MAX_AGE_HOURS" ]; then
            echo "Eski snapshot siliniyor: $snap_name ($age_hours saat)"
            # Mount edilmişse önce umount et
            umount "/dev/${VG}/${snap_name}" 2>/dev/null || true
            lvremove -f "/dev/${VG}/${snap_name}"
        fi
    fi
done

Crontab’a eklemek için:

# Crontab düzenle
crontab -e

# Her gece 02:00'da yedek al, her gün 06:00'da eski snapshot'ları temizle
0 2 * * * /usr/local/bin/lvm_backup.sh >> /var/log/lvm_backup.log 2>&1
0 6 * * * /usr/local/bin/snapshot_cleanup.sh >> /var/log/snapshot_cleanup.log 2>&1

Snapshot’tan Geri Yükleme

Snapshot aldınız, bir şeyler ters gitti ve geri dönmek istiyorsunuz. İki seçeneğiniz var.

Seçenek 1: Snapshot’tan doğrudan merge – Bu en hızlı yol ama dikkat ister. Volume önce umount edilmeli.

# Önce volume'ü umount et
umount /mnt/production

# Snapshot'ı merge et (orijinal volume snapshot anındaki haline döner)
lvconvert --merge /dev/vg_data/lv_production_snap

# Volume'ü tekrar aktive et
lvchange -an /dev/vg_data/lv_production
lvchange -ay /dev/vg_data/lv_production

# Mount et
mount /dev/vg_data/lv_production /mnt/production

Seçenek 2: Snapshot’tan belirli dosyaları kurtarma – Tüm volume’ü geri almak istemiyorsanız, sadece belirli dosyaları kurtarabilirsiniz.

# Snapshot'ı mount et
mount -o ro /dev/vg_data/lv_production_snap /mnt/recovery

# İstediğiniz dosyaları kopyalayın
cp /mnt/recovery/var/www/html/config.php /var/www/html/config.php
cp -r /mnt/recovery/home/user/important_dir /home/user/

# Temizlik
umount /mnt/recovery
lvremove -f /dev/vg_data/lv_production_snap

İkinci yöntem çok daha güvenli ve kontrollü. Özellikle “yanlışlıkla bir dosyayı sildim” durumlarında birebir.

Thin Provisioning ile Snapshot Kullanımı

Modern LVM kurulumlarında thin provisioning pool’u varsa, snapshot yönetimi çok daha esnek hale geliyor. Thin snapshot’lar hem daha verimli hem de boyut kısıtlaması olmadan oluşturulabiliyor.

# Thin pool oluştur (eğer yoksa)
lvcreate -L 200G --thinpool tp_main vg_data

# Thin volume oluştur
lvcreate -V 100G --thin -n lv_thin_prod vg_data/tp_main

# Thin snapshot al (boyut belirtmeye gerek yok)
lvcreate -s --name lv_thin_prod_snap vg_data/lv_thin_prod

# Thin snapshot listesi
lvs -a -o name,origin,data_percent vg_data

Thin snapshot’ın klasik snapshot’tan temel farkı: CoW verisi için ayrı bir alan belirtmiyorsunuz. Tüm thin volume’ler aynı pool’u paylaşıyor ve değişiklikler pool’dan tüketiliyor. Bu hem daha esnek hem de çok sayıda snapshot tutmak için çok daha pratik.

Monitoring ve Alerting

Snapshot doluluk oranını izlemek için basit bir monitoring scripti:

#!/bin/bash
# /usr/local/bin/check_snapshots.sh
# Bu scripti nagios/zabbix ya da basit cron ile çalıştırabilirsiniz

WARNING_THRESHOLD=70
CRITICAL_THRESHOLD=85
ALERT_EMAIL="[email protected]"

lvs --noheadings -o lv_name,data_percent --select "lv_attr =~ ^s" 2>/dev/null | while read lv_name data_percent; do
    # Yüzde işaretini kaldır
    usage=$(echo "$data_percent" | tr -d '%' | cut -d'.' -f1)
    
    if [ -z "$usage" ] || [ "$usage" = "" ]; then
        continue
    fi
    
    if [ "$usage" -ge "$CRITICAL_THRESHOLD" ]; then
        echo "KRITIK: Snapshot $lv_name doluluk orani %${usage}" | 
            mail -s "LVM Snapshot KRITIK Uyarisi" "$ALERT_EMAIL"
        echo "CRITICAL: $lv_name - %${usage} dolu"
    elif [ "$usage" -ge "$WARNING_THRESHOLD" ]; then
        echo "UYARI: Snapshot $lv_name doluluk orani %${usage}" | 
            mail -s "LVM Snapshot Uyarisi" "$ALERT_EMAIL"
        echo "WARNING: $lv_name - %${usage} dolu"
    else
        echo "OK: $lv_name - %${usage} dolu"
    fi
done

LVM’in kendi otomatik genişletme özelliğini de aktif edebilirsiniz. /etc/lvm/lvm.conf dosyasında:

# lvm.conf içinde snapshot_autoextend ayarları
# Bu satırları bulup düzenleyin
snapshot_autoextend_threshold = 70
snapshot_autoextend_percent = 20

Bu ayarla snapshot %70 dolduğunda, LVM otomatik olarak %20 daha alan ekliyor. Çok faydalı bir özellik, özellikle gece yarısı yedekleme sırasında kimse başında beklemiyorken.

Sık Yapılan Hatalar ve Çözümleri

Snapshot’ı silmeyi unutmak: En yaygın hata. Disk doluyor, kimse farkında değil, ta ki bir şeyler patlayana kadar. lvs -a | grep snap komutunu haftalık cron’a ekleyin ve çıktıyı mail olarak gönderin.

Yetersiz snapshot boyutu: Gece yedekleme başlıyor, sabah geliyorsunuz snapshot invalid olmuş. Yukarıda bahsettiğim formülü kullanın ve en az %50 güvenlik marjı bırakın.

Dosya sistemi tutarsızlığı: Snapshot alırken uygulama çalışmaya devam ediyorsa ve uygulamanın kendi write cache’i varsa, tutarsız snapshot alabilirsiniz. Kritik uygulamalar için kısa süreli freeze ya da uygulama seviyesinde flush yapmayı ihmal etmeyin.

Mount edilmiş snapshot’ı silmeye çalışmak: lvremove önce umount etmenizi bekler. Hata alıyorsanız lsof /mnt/snap_noktasi ile kimin mount’u tuttuğuna bakın.

Sonuç

LVM snapshot, üretim sistemlerinde kesintisiz yedekleme almanın en temiz yollarından biri. Temel prensibi basit: anlık görüntü al, bu görüntü üzerinden yedekle, görüntüyü sil. Ama pratikte boyut hesabı, otomatik temizlik, izleme ve veritabanı tutarlılığı gibi detaylar işin içine giriyor.

Bu yazıda ele aldığım konuları özetlersek: snapshot boyutunu iş yüküne göre hesaplayın, her zaman cleanup mekanizması kurun, snapshot’ı yedekle karıştırmayın, doluluk oranını izleyin ve thin provisioning seçeneğini değerlendirin.

Gerçek bir yedekleme stratejisinde LVM snapshot genellikle Bacula, Amanda ya da rsnapshot gibi araçlarla birlikte kullanılır. Snapshot, yedekleme penceresini küçültmek ve tutarlılık sağlamak için araç; gerçek depolama ve rotasyon mantığı ayrı bir katmanda yönetilir.

Sisteminizde LVM yoksa ve NVMe disklerle modern bir kurulum yapıyorsanız, ZFS snapshot’larını da araştırmanızı öneririm. Ama mevcut bir RHEL/CentOS/Debian kurulumunda LVM zaten genellikle hazır geliyor ve burada anlattıklarım hemen uygulanabilir durumda.

Yorum yapın