Ç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
--deleteiç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.
