Arşiv İşlemlerinde Dosya Filtreleme: mtime, size ve atime Kriterlerine Göre Seçici Yedekleme

Yıllar içinde öğrendiğim şeylerden biri şu: yedekleme sistemleri zamanla şişer. Başta “her şeyi yedekle” mantığıyla kurulan bir yapı, altı ay sonra terabaytlarca gereksiz veriyle dolmuş disk alanına ve saatlerce süren backup pencerelerine dönüşür. Bunun çözümü akıllı filtreleme, yani neyin yedekleneceğini dosya özelliklerine göre belirlemek.

Bu yazıda find komutuyla tar, rsync ve benzeri araçları birleştirerek mtime (değiştirilme zamanı), atime (erişim zamanı) ve size (dosya boyutu) kriterlerine göre seçici yedekleme yapmanın pratik yollarını paylaşacağım. Doğrudan production ortamlarından aldığım örnekler olacak, teorik değil.

Neden Seçici Yedekleme?

Klasik tam yedekleme (full backup) yaklaşımı her zaman mantıklı değil. Bir web sunucusunda /var/www altındaki statik asset’lerin büyük çoğunluğu aylardır değişmemiş olabilir. Bunları her gece yeniden arşivlemek hem zaman hem de depolama alanı israfıdır.

Seçici yedeklemenin bize kazandırdığı şeyler:

  • Zaman tasarrufu: Sadece değişen dosyaları arşivlemek backup süresini dramatik biçimde kısaltır
  • Depolama optimizasyonu: Gereksiz veri taşımadan kurtulursunuz
  • Bant genişliği: Uzak yedekleme lokasyonlarına daha az veri aktarırsınız
  • Granüler kontrol: Büyük log dosyalarını veya geçici dosyaları otomatik olarak dışarıda bırakabilirsiniz

find Komutunun Temel Zaman Kriterleri

find komutunu iyi bilmeden seçici yedekleme yapamazsınız. Üç temel zaman parametresini anlamak şart.

-mtime n: Son değiştirilme zamanına göre filtreler. Dosyanın içeriği veya metadata’sı değiştiğinde güncellenir.

-atime n: Son erişim zamanına göre filtreler. Dosya okunduğunda değişir, ancak modern sistemlerde relatime mount seçeneği nedeniyle her okumada güncellenmeyebilir.

-ctime n: İnode değişim zamanı. İzin değişiklikleri, sahiplik değişiklikleri dahil her türlü metadata değişikliğinde güncellenir.

Zaman değerlerinin mantığı biraz karışık gelir ilk başta:

  • -mtime 0: Bugün değişenler (son 24 saat)
  • -mtime -7: Son 7 gün içinde değişenler
  • -mtime +30: 30 günden daha önce değişenler
  • -mtime +30 -mtime -60: 30 ile 60 gün arasında değişenler

Artı ve eksi işaretleri kafayı karıştırır ama mantığı şu: artı “daha büyük”, eksi “daha küçük” demek. +30 demek “30 günden daha eski”, -7 demek “7 günden daha yeni”.

Pratik Senaryo 1: Günlük Incremental Yedekleme

Bir müşteri sunucusunda her gece çalışan bu yapıyı kullanıyoruz. Amaç sadece son 24 saat içinde değişmiş dosyaları arşivlemek.

#!/bin/bash
TARIH=$(date +%Y%m%d_%H%M%S)
KAYNAK="/var/www/html"
HEDEF="/backup/incremental"
ARSIV_ADI="incremental_${TARIH}.tar.gz"

# Son 24 saatte değişmiş dosyaları bul ve arşivle
find "${KAYNAK}" -type f -mtime -1 -print0 | 
  tar --null -czf "${HEDEF}/${ARSIV_ADI}" 
      --files-from=/dev/stdin 
      --no-recursion

echo "Arşiv oluşturuldu: ${HEDEF}/${ARSIV_ADI}"
echo "Boyut: $(du -sh ${HEDEF}/${ARSIV_ADI} | cut -f1)"

Burada --null ve -print0 kombinasyonu çok önemli. Dosya adlarında boşluk veya özel karakter varsa bu olmadan betik patlar. Production’da bunu atlayıp sonradan acı çeken insanlar gördüm.

Pratik Senaryo 2: Boyuta Göre Filtreleme

Büyük dosyaları yedek dışında tutmak ya da tam tersi sadece belirli boyutun üzerindeki dosyaları yedeklemek sık karşılaşılan bir ihtiyaç. -size parametresi burada devreye girer.

Boyut suffixes:

  • c: Byte
  • k: Kilobyte (1024 byte)
  • M: Megabyte
  • G: Gigabyte
# 100MB'dan küçük, son 7 günde değişmiş dosyaları yedekle
find /data/uploads 
  -type f 
  -mtime -7 
  -size -100M 
  -not -name "*.tmp" 
  -not -name "*.log" 
  -print0 | tar --null -czf /backup/uploads_$(date +%Y%m%d).tar.gz --files-from=/dev/stdin --no-recursion

Tersine, sadece büyük dosyaları izlemek istediğinizde de kullanışlı:

# 1GB'dan büyük dosyaları tespit et ve listele (yedek öncesi kontrol)
find /var /home /opt -type f -size +1G -printf "%st%pn" | 
  sort -rn | 
  awk '{printf "%.2f GBt%sn", $1/1073741824, $2}'

Bu komutu yedekleme öncesi çalıştırıp hangi büyük dosyaların sisteminizde olduğunu görmek, strateji geliştirmenize yardım eder.

Pratik Senaryo 3: atime ile Erişilmemiş Dosyaları Tespit Etme

atime kriteri biraz farklı bir kullanım alanına sahip. Uzun süredir kimsenin erişmediği dosyaları tespit edip arşivlemek veya temizlemek için idealdir. Bunu özellikle home directory temizliği ve eski log arşivleme için kullanıyorum.

# 90 günden uzun süredir erişilmemiş dosyaları listele
find /home -type f -atime +90 -printf "%AY-%Am-%Ad %pn" | 
  sort | head -50

Dikkat: Birçok modern Linux sistemi mount seçeneklerinde relatime kullanır. Bu durumda atime her okumada güncellenmez, yalnızca mevcut atime değeri mtime veya ctime‘dan eskiyse güncellenir. /proc/mounts veya mount komutuyla sisteminizin nasıl mount edildiğini kontrol edin.

# Mount seçeneklerini kontrol et
mount | grep -E "relatime|noatime|strictatime"

# Veya daha detaylı
cat /proc/mounts | awk '{print $2, $4}' | grep -E "relatime|atime"

Eğer noatime görüyorsanız atime tabanlı filtreleme çalışmaz, stratejinizi mtime‘a dayandırmanız gerekir.

Pratik Senaryo 4: Çoklu Kriter ile Karmaşık Filtreler

Gerçek dünya senaryoları genellikle tek bir kritere sığmaz. İşte bir e-ticaret sunucusunda kullandığımız yedekleme yapısından bir örnek:

#!/bin/bash
# Karmaşık filtreleme: mtime + size + uzantı kombinasyonu

KAYNAK="/var/www/eticaret"
HEDEF="/nfs/backup"
TARIH=$(date +%Y%m%d)

# Medya dosyaları hariç, son 48 saatte değişmiş, 50MB altı dosyalar
find "${KAYNAK}" 
  -type f 
  -mtime -2 
  -size -50M 
  ( -not -name "*.jpg" 
     -not -name "*.jpeg" 
     -not -name "*.png" 
     -not -name "*.mp4" 
     -not -name "*.mov" ) 
  -print0 > /tmp/yedek_listesi_${TARIH}.txt

# Kaç dosya bulundu?
DOSYA_SAYISI=$(cat /tmp/yedek_listesi_${TARIH}.txt | tr '' 'n' | wc -l)
echo "Yedeklenecek dosya sayısı: ${DOSYA_SAYISI}"

# Arşivle
tar --null -czf "${HEDEF}/web_${TARIH}.tar.gz" 
    --files-from=/tmp/yedek_listesi_${TARIH}.txt 
    --no-recursion

# Geçici dosyayı temizle
rm /tmp/yedek_listesi_${TARIH}.txt

Medya dosyalarını bu listeden çıkardık çünkü onlar için ayrı bir CDN yedekleme stratejimiz var. Bu tür ayrıştırma, büyük projelerde şart.

rsync ile Zaman Tabanlı Seçici Senkronizasyon

rsync kendi başına son değişiklik zamanına göre senkronize eder, ama find ile birleştirince çok daha güçlü hale gelir.

# Son 3 günde değişmiş dosyaları uzak sunucuya rsync ile aktar
find /data/projeler -type f -mtime -3 -print0 | 
  rsync --files-from=- 
        --from0 
        -avz 
        --no-relative 
        /data/projeler/ 
        kullanici@backup-sunucu:/backup/projeler/

Alternatif olarak rsync’in kendi --update ve --checksum parametrelerini de kullanabilirsiniz, ancak bunlar büyük dosya havuzlarında yavaş olabilir.

# rsync ile incremental, değişen dosyaları gözlemle
rsync -avz 
      --update 
      --log-file=/var/log/rsync_backup.log 
      --exclude="*.tmp" 
      --exclude="*.log" 
      --exclude=".git" 
      /var/www/ 
      [email protected]:/backup/www/

Haftalık Temizlik ve Arşivleme Scripti

Şu anda birkaç müşteri sunucusunda aktif olan, haftalık çalışan kapsamlı bir betik:

#!/bin/bash
# Haftalık seçici arşivleme ve temizlik betiği
# Cron: 0 2 * * 0 /opt/scripts/haftalik_arsiv.sh

set -euo pipefail

LOG="/var/log/haftalik_arsiv.log"
TARIH=$(date +%Y%m%d)
YEDEK_DIZIN="/backup/haftalik"
UYGULAMA_DIZIN="/opt/uygulamalar"

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

log "Haftalık arşivleme başladı"

# 1. Son 7 günde değişmiş konfigürasyon dosyalarını yedekle
log "Konfigürasyon dosyaları aranıyor..."
find /etc -type f 
  ( -name "*.conf" -o -name "*.cfg" -o -name "*.ini" ) 
  -mtime -7 
  -print0 | tar --null -czf "${YEDEK_DIZIN}/etc_conf_${TARIH}.tar.gz" 
                --files-from=/dev/stdin --no-recursion 2>/dev/null || true

# 2. 30 günden eski, 10MB üzeri log dosyalarını sıkıştır
log "Eski log dosyaları sıkıştırılıyor..."
find /var/log -type f -name "*.log" -mtime +30 -size +10M | while read -r dosya; do
    if [ -f "${dosya}" ]; then
        gzip -9 "${dosya}"
        log "Sıkıştırıldı: ${dosya}"
    fi
done

# 3. 90 günden eski sıkıştırılmış logları arşivle
log "Eski loglar arşivleniyor..."
find /var/log -type f -name "*.gz" -mtime +90 -print0 | 
  tar --null -czf "${YEDEK_DIZIN}/old_logs_${TARIH}.tar.gz" 
      --files-from=/dev/stdin --no-recursion 2>/dev/null || true

log "Haftalık arşivleme tamamlandı"
log "Oluşturulan arşivler:"
ls -lh "${YEDEK_DIZIN}/"*"${TARIH}"* 2>/dev/null | tee -a "${LOG}"

find ile Dosya Listesi Oluşturma ve tar’a Besleme

Büyük yedekleme işlerinde önce listeyi oluşturup sonra arşivlemek, hata ayıklamayı kolaylaştırır ve işlemi tekrar çalıştırmayı mümkün kılar.

# Adım 1: Listeyi oluştur ve kontrol et
find /data -type f -mtime -7 -size +1k -size -500M 
  -not -path "*/.git/*" 
  -not -path "*/node_modules/*" 
  -not -name "*.pyc" 
  > /tmp/yedek_listesi.txt

echo "Toplam dosya: $(wc -l < /tmp/yedek_listesi.txt)"
echo "Toplam boyut: $(cat /tmp/yedek_listesi.txt | xargs du -sc 2>/dev/null | tail -1)"

# Adım 2: Listeyi gözden geçir (opsiyonel)
head -20 /tmp/yedek_listesi.txt

# Adım 3: Arşivle
tar -czf /backup/data_$(date +%Y%m%d).tar.gz 
    --files-from=/tmp/yedek_listesi.txt 
    --no-recursion 
    --ignore-failed-read

echo "Çıkış kodu: $?"

--ignore-failed-read bayrağı özellikle önemli: bir dosya arşivleme sırasında silinirse veya erişilemez hale gelirse tüm işlemi durdurmak yerine devam etmesini sağlar.

Zaman Dilimi ve Timestamp Tuzakları

Bu konuda birkaç kez acı çektim, paylaşmadan geçemeyeceğim. find‘ın zaman hesaplamaları tam günler üzerinden çalışır, saatler üzerinden değil. -mtime -1 “son 24 saat” değil, “son 1 tam gün” demektir. Daha hassas zaman kontrolü için -newer parametresini kullanın:

# Belirli bir dosyadan daha yeni olan dosyaları bul
touch -t 202401150800 /tmp/referans_zaman
find /var/www -type f -newer /tmp/referans_zaman -print0 | 
  tar --null -czf /backup/sonraki_$(date +%Y%m%d%H%M).tar.gz 
      --files-from=/dev/stdin --no-recursion

# Veya doğrudan tarih referansıyla
find /opt -type f -newer /etc/passwd

-newermt parametresi ile string tarih de kullanabilirsiniz:

# 15 Ocak 2024 saat 08:00'den sonra değişmiş dosyalar
find /home -type f -newermt "2024-01-15 08:00:00"

Yedekleme Bütünlüğü Kontrolü

Oluşturulan arşivlerin sağlıklı olup olmadığını doğrulamak, yedekleme sürecinin ayrılmaz parçası olmalı.

#!/bin/bash
# Arşiv bütünlük kontrolü

ARSIV=$1

if [ -z "${ARSIV}" ]; then
    echo "Kullanım: $0 <arsiv.tar.gz>"
    exit 1
fi

echo "Arşiv kontrol ediliyor: ${ARSIV}"

# Bütünlük testi
if tar -tzf "${ARSIV}" > /dev/null 2>&1; then
    echo "BASARILI: Arşiv geçerli"
    echo "Dosya sayısı: $(tar -tzf ${ARSIV} | wc -l)"
    echo "Arşiv boyutu: $(du -sh ${ARSIV} | cut -f1)"
else
    echo "HATA: Arşiv bozuk veya okunamıyor!"
    exit 1
fi

# MD5 checksum oluştur (ilk çalıştırmada)
if [ ! -f "${ARSIV}.md5" ]; then
    md5sum "${ARSIV}" > "${ARSIV}.md5"
    echo "MD5 checksum oluşturuldu: ${ARSIV}.md5"
fi

Performans ve Dikkat Edilmesi Gerekenler

Büyük dosya sistemlerinde find çalıştırırken birkaç noktaya dikkat etmek gerekiyor:

  • -maxdepth kullanımı: Gereksiz derin dizi taramalarından kaçınmak için dizin derinliğini sınırlayın
  • -xdev bayrağı: Find komutunun farklı filesystem’lere geçmesini önler, NFS mount’larının yanlışlıkla taranmasını engeller
  • Sıralama önemi: find komutunda -prune ile büyük dizinleri erken eleyebilirsiniz
# NFS veya diğer mount'lara geçmeden, sadece yerel filesystem
find /data -xdev -type f -mtime -7 -size -200M -print0 | 
  tar --null -czf /backup/local_data_$(date +%Y%m%d).tar.gz 
      --files-from=/dev/stdin --no-recursion

# node_modules ve .git gibi büyük dizinleri atla
find /opt/uygulamalar 
  -type d ( -name node_modules -o -name .git -o -name __pycache__ ) -prune 
  -o -type f -mtime -3 -print0 | 
  tar --null -czf /backup/app_$(date +%Y%m%d).tar.gz 
      --files-from=/dev/stdin --no-recursion

-prune kullanımında -o sonrasındaki asıl koşulun -print0 ile sonlandırılması gerektiğini unutmayın, yoksa atlanacak dizinler de çıktıya dahil olur.

Sonuç

Seçici yedekleme, olgunlaşmış bir yedekleme stratejisinin göstergesidir. “Her şeyi yedekle” yaklaşımından “gerekeni, zamanında, verimli biçimde yedekle” yaklaşımına geçiş, hem operasyonel maliyeti düşürür hem de yedekleme pencerelerini kısaltarak sistem kullanılabilirliğini artırır.

Bu yazıda anlattıklarımı kendi ortamınıza uygularken şunları aklınızda tutun: İlk önce küçük bir test dizininde deneyin, -print0 ve --null kombinasyonunu asla atlamamayın ve oluşturduğunuz arşivlerin bütünlüğünü mutlaka doğrulayın. Bir yedekleme sisteminin değeri, onu hiç açmadığınız zamanlarda değil, tam da ihtiyaç duyduğunuz an ne kadar güvenilir olduğunda ortaya çıkar.

Zaman filtrelerini cron job’larla birleştirip farklı sıklıklarda çalıştırdığınızda, günlük incremental ve haftalık full yedekleme stratejisini neredeyse tamamen otomatize edebilirsiniz. Bu yapıyı bir kez doğru kurduğunuzda, yedekleme kaygısından kurtulup asıl işinize odaklanabilirsiniz.

Bir yanıt yazın

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