Çift Yönlü Senkronizasyon: rsync ile Veri Eşitleme

Veri yönetimi söz konusu olduğunda, tek yönlü yedekleme çoğu zaman yeterli olmaz. Birden fazla sunucu, birden fazla ofis veya birden fazla kullanıcının aynı veri seti üzerinde çalıştığı ortamlarda çift yönlü senkronizasyon hayati bir ihtiyaç haline gelir. rsync bu iş için güçlü bir araç olmakla birlikte, çift yönlü senaryolarda bazı incelikleri doğru anlamadan ilerlemek ciddi veri kayıplarına yol açabilir. Bu yazıda hem teorik temeli hem de gerçek dünya uygulamalarını ele alacağız.

Çift Yönlü Senkronizasyon Nedir ve Neden Karmaşıktır?

Tek yönlü senkronizasyonda kaynak her zaman doğrudur, hedef her zaman güncellenir. Basit ve öngörülebilir bir süreç. Ancak çift yönlü senkronizasyonda iki taraf da “kaynak” olabilir. İki lokasyonda aynı dosya bağımsız olarak değiştirilmişse ne olacak? Hangi versiyon kazanacak? Silinen bir dosya diğer tarafta da silinmeli mi, yoksa orada hâlâ geçerli mi?

rsync aslında doğası gereği tek yönlü bir araçtır. “Çift yönlü” senkronizasyon, iki ayrı rsync operasyonunu akıllıca yönetmekle elde edilir. Bu yüzden çakışma yönetimi (conflict resolution) konusunu atlamamak gerekir.

Gerçek hayatta karşılaşılan üç temel senaryo şunlardır:

  • İstanbul ofisindeki dosya güncellendi, Ankara ofisindeki de güncellendi, hangisi doğru?
  • Bir tarafta dosya silindi, diğer tarafta hâlâ var. Silinmeli mi, korunmalı mı?
  • Ağ kesintisi sırasında yarım kalan transfer sonrası tutarsızlık

Bu sorulara net cevaplar vermeden bir senkronizasyon sistemi kurmak, eninde sonunda veri kaybıyla sonuçlanır.

rsync Temel Parametrelerini Hatırlamak

Çift yönlü senaryolara geçmeden önce işimize yarayacak parametreleri gözden geçirelim:

  • -a (–archive): Arşiv modu; izinleri, zaman damgalarını, sembolik linkleri korur
  • -v (–verbose): İşlem detaylarını gösterir
  • -z (–compress): Transfer sırasında sıkıştırma yapar, yavaş bağlantılarda faydalı
  • -n (–dry-run): Gerçekten kopyalamaz, sadece ne yapılacağını gösterir
  • –delete: Kaynakta olmayan dosyaları hedeften siler
  • –backup: Üzerine yazılacak dosyaları yedekler
  • –backup-dir: Yedeklenen dosyaların gideceği dizin
  • –checksum: Boyut/tarih yerine MD5 kontrolü yapar, yavaş ama güvenilir
  • –exclude: Belirli dosya/dizinleri dışarıda bırakır
  • –log-file: İşlemleri log dosyasına yazar
  • –itemize-changes: Her dosya için ne yapıldığını ayrıntılı gösterir

Basit Çift Yönlü Senkronizasyon

En temel yaklaşım, iki ayrı rsync komutu çalıştırmaktır. Önce A’dan B’ye, sonra B’den A’ya.

#!/bin/bash
# basit_sync.sh - Tehlikeli! Sadece eğitim amaçlı

SITE_A="user@sunucu-istanbul:/data/paylasim/"
SITE_B="user@sunucu-ankara:/data/paylasim/"
LOG="/var/log/sync/basit_sync.log"

echo "[$(date)] Senkronizasyon başladı" >> $LOG

# A'dan B'ye
rsync -avz --delete 
  $SITE_A 
  $SITE_B >> $LOG 2>&1

# B'den A'ya
rsync -avz --delete 
  $SITE_B 
  $SITE_A >> $LOG 2>&1

echo "[$(date)] Senkronizasyon tamamlandı" >> $LOG

Bu yaklaşım neden tehlikelidir? Eğer ilk rsync çalışırken B tarafındaki bir dosya değiştirilirse ve ikinci rsync o eski veriyi A’ya yazdıysa, A’daki güncel veri kaybolur. Ayrıca --delete ile birlikte kullanıldığında, bir tarafta silinen dosya diğer taraftan da silinir ve bu her zaman istenen davranış olmayabilir.

Güvenli Yaklaşım: Yedek Dizinli Senkronizasyon

Üzerine yazma veya silme işlemlerinden önce mevcut versiyonları yedeklemek, geri dönüş imkânı tanır.

#!/bin/bash
# guvenli_sync.sh

SITE_A="/data/paylasim/"
SITE_B="user@sunucu-ankara:/data/paylasim/"
YEDEK_DIR="/data/yedek/sync_$(date +%Y%m%d_%H%M%S)"
LOG="/var/log/sync/guvenli_sync.log"

mkdir -p $YEDEK_DIR
echo "[$(date)] Güvenli senkronizasyon başladı" >> $LOG

# A'dan B'ye - üzerine yazılacakları yedekle
rsync -avz 
  --backup 
  --backup-dir="$YEDEK_DIR/b_yedek" 
  --log-file="$LOG" 
  $SITE_A 
  $SITE_B

# B'den A'ya - üzerine yazılacakları yedekle
rsync -avz 
  --backup 
  --backup-dir="$YEDEK_DIR/a_yedek" 
  --log-file="$LOG" 
  $SITE_B 
  $SITE_A

echo "[$(date)] Tamamlandı. Yedekler: $YEDEK_DIR" >> $LOG

# Eski yedekleri temizle (30 günden eski)
find /data/yedek/ -maxdepth 1 -type d -mtime +30 -exec rm -rf {} ;

Çakışma Tespiti ile Senkronizasyon

Gerçek bir çift yönlü senkronizasyon çözümü için dosyaların son değiştirilme zamanlarını karşılaştırmak gerekir. İşte daha gelişmiş bir yaklaşım:

#!/bin/bash
# akilli_sync.sh - Çakışma tespitli senkronizasyon

SITE_A_LOCAL="/data/paylasim/"
SITE_B_REMOTE="user@sunucu-ankara"
SITE_B_PATH="/data/paylasim/"
SITE_B_FULL="${SITE_B_REMOTE}:${SITE_B_PATH}"
CATISMA_DIR="/data/catismalar/$(date +%Y%m%d_%H%M%S)"
LOG="/var/log/sync/akilli_sync.log"
DURUM_DOSYASI="/var/lib/sync/son_sync.timestamp"

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

mkdir -p $CATISMA_DIR
mkdir -p $(dirname $DURUM_DOSYASI)

log "=== Akıllı senkronizasyon başladı ==="

# Son senkronizasyon zamanını al
if [ -f "$DURUM_DOSYASI" ]; then
    SON_SYNC=$(cat $DURUM_DOSYASI)
    log "Son senkronizasyon: $SON_SYNC"
else
    SON_SYNC="0"
    log "İlk senkronizasyon çalışıyor"
fi

# A tarafında değişen dosyaları bul
log "A tarafındaki değişiklikler tespit ediliyor..."
find $SITE_A_LOCAL -newer /proc/$$/fd/1 -type f 2>/dev/null | 
    grep -v ".sync_lock" > /tmp/a_degisen.txt

# Dry-run ile çakışma analizi
log "Çakışma analizi yapılıyor..."
rsync -avzn --itemize-changes 
    $SITE_A_LOCAL 
    $SITE_B_FULL 
    --log-file=/tmp/a_to_b_preview.log 2>&1

# Gerçek senkronizasyon
log "A'dan B'ye senkronizasyon..."
rsync -avz 
    --backup 
    --backup-dir="$CATISMA_DIR/onceki_b" 
    --itemize-changes 
    --log-file=$LOG 
    $SITE_A_LOCAL 
    $SITE_B_FULL

if [ $? -eq 0 ]; then
    log "A -> B başarılı"
else
    log "HATA: A -> B başarısız!"
    exit 1
fi

log "B'den A'ya senkronizasyon..."
rsync -avz 
    --backup 
    --backup-dir="$CATISMA_DIR/onceki_a" 
    --itemize-changes 
    --log-file=$LOG 
    $SITE_B_FULL 
    $SITE_A_LOCAL

if [ $? -eq 0 ]; then
    log "B -> A başarılı"
    date +%s > $DURUM_DOSYASI
else
    log "HATA: B -> A başarısız!"
    exit 1
fi

log "=== Senkronizasyon tamamlandı ==="

Gerçek Dünya Senaryosu 1: İki Ofis Arası Dosya Paylaşımı

İstanbul ve Ankara ofislerinde birer dosya sunucusu var. Her iki ofisteki kullanıcılar /srv/paylasim dizinine dosya ekliyor, düzenliyor ve siliyor. Her gece bu iki sunucunun senkronize edilmesi gerekiyor.

#!/bin/bash
# ofis_sync.sh - Günlük ofis senkronizasyonu
# Cron: 0 2 * * * /usr/local/bin/ofis_sync.sh

IST_PATH="/srv/paylasim/"
ANK_HOST="ankara-fs01"
ANK_PATH="/srv/paylasim/"
ANK_FULL="${ANK_HOST}:${ANK_PATH}"

LOG_DIR="/var/log/ofis_sync"
YEDEK_BASE="/srv/yedek"
TARIH=$(date +%Y%m%d_%H%M)
YEDEK_DIR="${YEDEK_BASE}/${TARIH}"
KILIT_DOSYASI="/var/run/ofis_sync.lock"

mkdir -p $LOG_DIR $YEDEK_DIR

# Çakışma kontrolü - başka bir sync çalışıyor mu?
if [ -f "$KILIT_DOSYASI" ]; then
    PID=$(cat $KILIT_DOSYASI)
    if kill -0 $PID 2>/dev/null; then
        echo "Senkronizasyon zaten çalışıyor (PID: $PID)" | 
            mail -s "Sync Uyarı - $HOSTNAME" [email protected]
        exit 1
    fi
fi
echo $$ > $KILIT_DOSYASI
trap "rm -f $KILIT_DOSYASI" EXIT

# SSH bağlantısını test et
if ! ssh -o ConnectTimeout=10 -o BatchMode=yes $ANK_HOST "echo ok" > /dev/null 2>&1; then
    echo "Ankara sunucusuna bağlanılamadı!" | 
        mail -s "KRITIK: Sync Başarısız - $(date)" [email protected]
    exit 1
fi

# Senkronizasyon parametreleri
RSYNC_OPTS="-avz 
    --backup 
    --backup-dir=${YEDEK_DIR} 
    --exclude='.~lock.*' 
    --exclude='*.tmp' 
    --exclude='.DS_Store' 
    --exclude='Thumbs.db' 
    --itemize-changes 
    --stats"

# İstanbul'dan Ankara'ya
rsync $RSYNC_OPTS 
    --log-file="${LOG_DIR}/ist_to_ank_${TARIH}.log" 
    $IST_PATH 
    $ANK_FULL

IST_ANK_SONUC=$?

# Ankara'dan İstanbul'a (yeni eklenenler)
rsync $RSYNC_OPTS 
    --log-file="${LOG_DIR}/ank_to_ist_${TARIH}.log" 
    $ANK_FULL 
    $IST_PATH

ANK_IST_SONUC=$?

# Sonuç raporu
if [ $IST_ANK_SONUC -eq 0 ] && [ $ANK_IST_SONUC -eq 0 ]; then
    MESAJ="Senkronizasyon başarılı. İst->Ank: OK, Ank->İst: OK"
else
    MESAJ="HATA! İst->Ank: $IST_ANK_SONUC, Ank->İst: $ANK_IST_SONUC"
fi

echo "$MESAJ - $(date)" | 
    mail -s "Ofis Sync Raporu - $TARIH" [email protected]

Gerçek Dünya Senaryosu 2: Web Sunucusu Clusteri

Yük dengeleyici arkasında iki web sunucusu çalışıyor ve /var/www/html dizininin her ikisinde de güncel olması gerekiyor.

#!/bin/bash
# web_cluster_sync.sh
# Web içerik senkronizasyonu - 5 dakikada bir çalışır

WEB1_PATH="/var/www/html/"
WEB2="web02.internal"
WEB2_PATH="/var/www/html/"
WEB2_FULL="${WEB2}:${WEB2_PATH}"
LOG="/var/log/web_sync.log"

# Web dosyaları için özel seçenekler
RSYNC_WEB="-az 
    --delete 
    --exclude='.git' 
    --exclude='*.log' 
    --exclude='cache/' 
    --exclude='tmp/' 
    --exclude='uploads/tmp/' 
    --compress-level=9 
    --checksum"

log_yaz() {
    echo "[$(date '+%H:%M:%S')] $1" >> $LOG
}

# Web02 erişilebilir mi?
if ! ping -c 1 -W 2 $WEB2 > /dev/null 2>&1; then
    log_yaz "UYARI: $WEB2 erişilemiyor, sync atlandı"
    exit 0
fi

# Önce dry-run ile değişiklik var mı bak
DEGISIKLIK=$(rsync $RSYNC_WEB -n --itemize-changes 
    $WEB1_PATH $WEB2_FULL 2>/dev/null | grep -c "^[<>]")

if [ "$DEGISIKLIK" -gt "0" ]; then
    log_yaz "$DEGISIKLIK dosya değişikliği tespit edildi"
    
    rsync $RSYNC_WEB 
        --log-file=$LOG 
        $WEB1_PATH 
        $WEB2_FULL
    
    log_yaz "Senkronizasyon tamamlandı"
else
    log_yaz "Değişiklik yok, atlandı"
fi

Unison ile Gerçek Çift Yönlü Senkronizasyon

rsync’in sınırlamalarını aşmak için Unison aracı devreye girer. Unison, çakışmaları otomatik veya kullanıcı onayıyla çözer ve rsync algoritmasını altında kullanır.

# Unison kurulumu
apt install unison        # Debian/Ubuntu
yum install unison        # RHEL/CentOS

# ~/.unison/ofis.prf profil dosyası
cat > ~/.unison/ofis.prf << 'EOF'
# İki yön
root = /srv/paylasim
root = ssh://ankara-fs01//srv/paylasim

# Otomatik mod (etkileşimsiz)
batch = true

# Çakışmada daha yeni dosyayı tercih et
prefer = newer

# Görmezden gelinecekler
ignore = Name .DS_Store
ignore = Name Thumbs.db
ignore = Name *.tmp
ignore = Name .~lock.*

# Log
log = true
logfile = /var/log/unison/ofis.log

# Silme işlemlerini yayma
confirmbigdel = false

# Sıkıştırma
rsync = true
EOF

# Çalıştırma
unison ofis

# Cron için
# 0 */4 * * * /usr/bin/unison ofis -silent

Loglama ve İzleme

Senkronizasyon işlemlerini izlemek ve sorunları erken fark etmek için kapsamlı loglama şarttır.

#!/bin/bash
# sync_monitor.sh - Sync sağlığını kontrol et

LOG_DIR="/var/log/ofis_sync"
ESIK_DAKIKA=1440  # 24 saat

# En son başarılı sync ne zaman?
SON_BASARILI=$(find $LOG_DIR -name "*.log" -newer /tmp/kontrol 
    -exec grep -l "total size is" {} ; | sort | tail -1)

if [ -z "$SON_BASARILI" ]; then
    echo "KRITIK: 24 saat içinde başarılı sync yok!" | 
        mail -s "ALARM: Sync Durdu!" [email protected]
    exit 2
fi

# Log boyutu anormallikleri
SON_LOG=$(ls -t $LOG_DIR/*.log 2>/dev/null | head -1)
if [ -f "$SON_LOG" ]; then
    HATA_SAYISI=$(grep -c "ERROR|FAILED|rsync error" $SON_LOG 2>/dev/null || echo 0)
    
    if [ "$HATA_SAYISI" -gt "5" ]; then
        echo "Dikkat: Son sync logunda $HATA_SAYISI hata var" | 
            mail -s "Sync Uyarı" [email protected]
    fi
    
    # İstatistikleri çıkar
    grep "Number of files" $SON_LOG
    grep "Total transferred" $SON_LOG
    grep "Total bytes sent" $SON_LOG
fi

# Disk kullanımı kontrolü
DISK_DOLULUK=$(df /srv/paylasim | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$DISK_DOLULUK" -gt "85" ]; then
    echo "UYARI: /srv/paylasim disk doluluk: %$DISK_DOLULUK" | 
        mail -s "Disk Uyarısı" [email protected]
fi

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

Sonundaki slash (/) karakterini yanlış kullanmak rsync kullanıcılarının en sık yaptığı hatadır.

# YANLIŞ - dizin içine dizin oluşturur
rsync -av /kaynak /hedef/
# Sonuç: /hedef/kaynak/dosyalar

# DOĞRU - dizin içeriğini kopyalar
rsync -av /kaynak/ /hedef/
# Sonuç: /hedef/dosyalar

–delete kullanırken dikkat:

# Önce mutlaka dry-run yap!
rsync -avzn --delete /kaynak/ user@sunucu:/hedef/

# Çıktıyı incele, sonra gerçeği çalıştır
rsync -avz --delete /kaynak/ user@sunucu:/hedef/

Bandwidth sınırlama – Canlı ortamda ağı boğmamak için:

# 10 MB/s ile sınırla
rsync -avz --bwlimit=10240 /kaynak/ user@sunucu:/hedef/

Cron Entegrasyonu ve Üretim Hazırlığı

# /etc/cron.d/ofis-sync
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
[email protected]

# Her gece 02:00'de çalış
0 2 * * * root /usr/local/bin/ofis_sync.sh >> /var/log/ofis_sync/cron.log 2>&1

# Web cluster sync - 5 dakikada bir
*/5 * * * * www-data /usr/local/bin/web_cluster_sync.sh

# Eski yedekleri temizle - her Pazar
0 4 * * 0 root find /srv/yedek -type d -mtime +30 -exec rm -rf {} ; 2>/dev/null

Systemd timer tercih ediyorsanız:

# /etc/systemd/system/ofis-sync.service
[Unit]
Description=Ofis Senkronizasyonu
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ofis_sync.sh
User=root

# /etc/systemd/system/ofis-sync.timer
[Unit]
Description=Ofis Sync Timer

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Sonuç

rsync ile çift yönlü senkronizasyon, doğru tasarlanmadığında veri kaybına davetiye çıkaran bir süreçtir. Başarılı bir kurulum için şu ilkeleri unutmamak gerekir:

  • Her zaman dry-run ile başla, özellikle --delete içeren komutlarda
  • Yedek dizinleri kullan (--backup --backup-dir), üzerine yazmadan önce eski versiyonu sakla
  • Kilit dosyası mekanizması ekle, çakışan çalışmaları önle
  • SSH bağlantısını test et, ağ sorununda sync’i atlayıp devam et
  • Her adımı logla, sorun çıktığında geri dönebilesin
  • Karmaşık çakışma senaryoları için Unison gibi özel araçları değerlendir
  • Senkronizasyon sağlığını izleme sistemiyle takip et, susmakta kalan sync süreçlerini erken yakala

Çift yönlü senkronizasyon hiçbir zaman tek satır bir çözüm değildir. Ne kadar düşünülmüş olursa o kadar güvenilir olur. Yukarıdaki betikleri kendi ortamınıza uyarlayın, önce test sunucularında deneyin, production’a almadan önce birkaç manuel çalıştırma yapın ve log dosyalarını inceleyin.

Bir yanıt yazın

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