Rsync Hata Ayıklama ve Log Yönetimi

Yedekleme işlemlerinde en çok sinir bozan şey nedir biliyor musun? Sabah işe geliyorsun, gece çalışması gereken rsync job’ı başarısız olmuş, ama neden başarısız olduğunu anlamak için saatler harcıyorsun. Log yok, hata mesajı belirsiz, ya da tam tersine o kadar çok log var ki içinden çıkamıyorsun. İşte bu yazıda rsync’in hata ayıklama mekanizmalarını ve log yönetimini derinlemesine inceleyeceğiz. Gerçek dünyada karşılaşılan sorunları ele alacağız ve “bu neden çalışmıyor?” sorusuna sistematik cevaplar bulmayı öğreneceğiz.

Rsync’in Çıkış Kodlarını Anlamak

Rsync her çalışma sonucunda bir çıkış kodu döndürür. Bu kodları anlamak, otomatik yedekleme scriptlerinde hata yönetiminin temelini oluşturur.

En sık karşılaşılan çıkış kodları şunlardır:

  • 0: Başarılı tamamlama
  • 1: Sözdizimi veya kullanım hatası
  • 2: Protokol uyumsuzluğu
  • 3: Giriş/çıkış hatası (dosya seçiminde)
  • 5: Başlatma hatası
  • 10: Soket I/O hatası (ağ bağlantısı koptu)
  • 11: Dosya I/O hatası
  • 12: Rsync protokol veri akışı hatası
  • 23: Bazı dosyalar aktarılamadı (kısmi başarı)
  • 24: Bazı dosyalar aktarım sırasında silindi (kaynak değişti)
  • 25: –max-delete limiti aşıldı
  • 30: Zaman aşımı hatası
  • 35: Bağlantı zaman aşımı

Özellikle kod 23 çok önemlidir. Pek çok sysadmin bu kodu görünce “bir şeyler yanlış gitti” diye panikler, oysa bu sadece bazı dosyaların atlındığını gösterir. Belki bir dosya aktarım sırasında değişti, belki izin sorunu vardı. Kritik mi değil mi, bunu log’a bakarak anlayacaksın.

#!/bin/bash
# Çıkış kodu kontrolü ile akıllı yedekleme scripti

rsync -avz --delete /data/web/ [email protected]:/backup/web/
EXIT_CODE=$?

case $EXIT_CODE in
    0)
        echo "$(date): Yedekleme başarıyla tamamlandı" >> /var/log/backup.log
        ;;
    23)
        echo "$(date): UYARI - Bazı dosyalar aktarılamadı (kod 23), detay için rsync.log kontrol edin" >> /var/log/backup.log
        # Kod 23'ü kritik hata saymıyoruz ama bildiriyoruz
        exit 0
        ;;
    24)
        echo "$(date): UYARI - Bazı dosyalar aktarım sırasında değişti (kod 24)" >> /var/log/backup.log
        exit 0
        ;;
    *)
        echo "$(date): KRİTİK HATA - Rsync başarısız oldu, çıkış kodu: $EXIT_CODE" >> /var/log/backup.log
        # Alarm gönder
        mail -s "Yedekleme Başarısız! Sunucu: $(hostname)" [email protected] < /var/log/backup.log
        exit 1
        ;;
esac

Verbose ve Debug Seçenekleri

Rsync’in ne yaptığını görmek için çeşitli verbosity seviyeleri vardır.

  • -v: Temel verbose, hangi dosyaların transfer edildiğini gösterir
  • -vv: Daha ayrıntılı çıktı, atlanan dosyalar dahil
  • -vvv: Maximum debug seviyesi, protokol detayları
  • –progress: Aktif transfer ilerlemesini gösterir
  • –stats: Transfer istatistiklerini özetle gösterir
  • –itemize-changes: Her dosya için ne yapıldığını gösterir (çok güçlü!)
  • –dry-run (-n): Gerçekte hiçbir şey yapmadan neyin olacağını gösterir

--itemize-changes seçeneği özellikle güçlüdür. Her dosya için 11 karakterlik bir format kodu gösterir:

# itemize-changes çıktısını anlama
rsync -avzn --itemize-changes /source/ /destination/

# Örnek çıktı:
# >f.st...... dosya.txt   -> dosya değişti (boyut veya zaman)
# >f++++++++++ yeni_dosya.txt -> yeni dosya eklendi
# .d..t....... dizin/    -> dizin zamanı değişti
# *deleting   eski_dosya.txt -> silinecek dosya

# Format: YXcstpoguax
# Y: > (transfer edilecek), < (alınacak), c (yerel değişim), h (hard link), . (değişim yok)
# X: f (dosya), d (dizin), L (symlink), D (cihaz), S (özel dosya)
# c: checksum farklı
# s: boyut farklı
# t: zaman farklı
# p: izinler farklı
# o: sahip farklı
# g: grup farklı

Log Dosyası Yapılandırması

Rsync’in log yönetimi için birkaç farklı yaklaşım mevcuttur.

–log-file Kullanımı

En basit yaklaşım --log-file parametresidir:

rsync -avz 
    --log-file=/var/log/rsync/backup_$(date +%Y%m%d).log 
    --log-file-format="%t [%p] %o %f %l" 
    /data/ [email protected]:/backup/

# Log format parametreleri:
# %t: zaman damgası
# %p: PID
# %o: operasyon (send/recv/del)
# %f: dosya adı
# %l: dosya boyutu
# %b: transfer edilen byte sayısı
# %e: hata kodu (varsa)
# %i: itemize kodu

Gelişmiş Log Yapısı

Üretim ortamlarında log dosyalarını düzenli tutmak önemlidir. Tarih bazlı log yapısı kuralım:

#!/bin/bash
# /usr/local/bin/rsync-backup.sh

LOG_DIR="/var/log/rsync"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$LOG_DIR/backup_${DATE}.log"
SUMMARY_FILE="$LOG_DIR/summary.log"

# Log dizinini oluştur
mkdir -p "$LOG_DIR"

# Rsync komutu
rsync -avz 
    --delete 
    --stats 
    --log-file="$LOG_FILE" 
    --log-file-format="%t [%i] [%o] %n%L (%b bytes)" 
    --exclude='*.tmp' 
    --exclude='*.cache' 
    --exclude='.git/' 
    /var/www/html/ 
    [email protected]:/backup/web/ 2>&1

EXIT_CODE=$?

# Özet bilgiyi summary log'a ekle
echo "$(date '+%Y-%m-%d %H:%M:%S') | Exit: $EXIT_CODE | Log: $LOG_FILE" >> "$SUMMARY_FILE"

# 30 günden eski logları temizle
find "$LOG_DIR" -name "backup_*.log" -mtime +30 -delete

exit $EXIT_CODE

Rsyncd Sunucu Tarafı Log Yönetimi

Eğer rsync daemon modunda (rsyncd) çalışıyorsa, sunucu tarafında da log yönetimi yapman gerekir.

/etc/rsyncd.conf dosyasında log yapılandırması:

# /etc/rsyncd.conf
uid = rsync
gid = rsync
use chroot = yes
max connections = 4
pid file = /var/run/rsyncd.pid

# Global log ayarları
log file = /var/log/rsyncd.log
log format = %t %a %m %f %b
transfer logging = yes
syslog facility = local5

[web_backup]
    path = /backup/web
    comment = Web Sunucu Yedekleri
    read only = no
    auth users = webbackup
    secrets file = /etc/rsyncd.secrets
    # Modül bazlı log
    log file = /var/log/rsync/web_backup.log
    refuse options = checksum delete

Syslog entegrasyonu için /etc/rsyslog.d/rsync.conf dosyası oluşturabilirsin:

# /etc/rsyslog.d/rsync.conf
local5.*    /var/log/rsync/rsyncd.log

# Bu ayarın ardından rsyslog'u yeniden başlat
systemctl restart rsyslog

Gerçek Dünya Senaryosu 1: “Transfer Çok Yavaş” Sorunu

Bir müşteri aramı aradı, “gece yedeklemesi 2 saatte bitiyordu, şimdi 8 saate çıktı” dedi. Teşhis süreci şöyle oldu:

# Önce --stats ile genel bir bakış
rsync -avz --stats --dry-run /data/production/ [email protected]:/backup/ 2>&1 | tee /tmp/rsync_stats.txt

# Çıktıyı incele
grep -E "(files|bytes|speedup)" /tmp/rsync_stats.txt

# Checkpoint: Her N dosyadan sonra ilerlemeyi göster
rsync -avz --info=progress2 /data/production/ [email protected]:/backup/

# Bant genişliğini ölç
rsync -avz --bwlimit=0 --stats /data/production/ [email protected]:/backup/ 2>&1 | grep "bytes/sec"

Sorun ortaya çıktı: Biri production sunucusuna 47 GB’lık log dosyası bırakmıştı ve bu dosya her gece transfer ediliyordu. --exclude ile çözdük ama asıl önemli olan log analizi sayesinde bunu hızlıca tespit edebildik.

# Büyük dosyaları tespit etmek için
rsync -avzn --out-format="%l %n" /data/production/ [email protected]:/backup/ | 
    sort -rn | head -20

Gerçek Dünya Senaryosu 2: SSH Bağlantı Hataları

Uzak rsync işlemlerinde SSH kaynaklı sorunlar çok yaygındır. Debug yaklaşımı:

# SSH bağlantısını ayrı test et
ssh -v [email protected] "echo SSH OK"

# Rsync'e SSH debug parametresi geç
rsync -avz -e "ssh -v -i /root/.ssh/backup_key" 
    /data/ [email protected]:/backup/ 2>&1 | tee /tmp/rsync_ssh_debug.log

# SSH timeout sorunları için
rsync -avz -e "ssh -o ConnectTimeout=30 -o ServerAliveInterval=60 -o ServerAliveCountMax=3" 
    /data/ [email protected]:/backup/

# StrictHostKeyChecking sorunu (ilk bağlantı)
rsync -avz -e "ssh -o StrictHostKeyChecking=no" 
    /data/ [email protected]:/backup/

Genellikle karşılaşılan SSH hata mesajları ve çözümleri:

  • “Host key verification failed”: ssh-keyscan -H 192.168.1.100 >> ~/.ssh/known_hosts ile çöz
  • “Permission denied (publickey)”: SSH anahtar dosyasının izinlerini kontrol et, chmod 600 ~/.ssh/backup_key olmalı
  • “Connection timed out”: Firewall kurallarını kontrol et, sunucu tarafında port 22 açık mı?
  • “Broken pipe”: ServerAliveInterval ve ServerAliveCountMax ile SSH keepalive ayarla

Hata Toleranslı Yedekleme Scripti

Tüm bu bilgileri birleştiren, production ortamına hazır bir script:

#!/bin/bash
# /usr/local/bin/smart-backup.sh
# Kullanım: ./smart-backup.sh <kaynak> <hedef> <job_adı>

set -euo pipefail

# Yapılandırma
SOURCE="${1:-/data}"
DEST="${2:[email protected]:/backup}"
JOB_NAME="${3:-backup}"
LOG_DIR="/var/log/rsync"
MAX_RETRY=3
RETRY_DELAY=60
MAIL_TO="[email protected]"

# Renkli çıktı
RED='33[0;31m'
YELLOW='33[1;33m'
GREEN='33[0;32m'
NC='33[0m'

# Loglama fonksiyonu
log() {
    local level="$1"
    local message="$2"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${timestamp} [${level}] ${message}" | tee -a "$LOG_FILE"
}

# Log dosyasını hazırla
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/${JOB_NAME}_$(date +%Y%m%d_%H%M%S).log"
LOCK_FILE="/tmp/rsync_${JOB_NAME}.lock"

# Çakışma kontrolü
if [ -f "$LOCK_FILE" ]; then
    OLD_PID=$(cat "$LOCK_FILE")
    if kill -0 "$OLD_PID" 2>/dev/null; then
        log "ERROR" "Başka bir $JOB_NAME işlemi çalışıyor (PID: $OLD_PID)"
        exit 1
    else
        log "WARN" "Eski lock dosyası temizleniyor"
        rm -f "$LOCK_FILE"
    fi
fi

echo $$ > "$LOCK_FILE"
trap "rm -f $LOCK_FILE" EXIT

# Retry mekanizması
attempt=0
while [ $attempt -lt $MAX_RETRY ]; do
    attempt=$((attempt + 1))
    log "INFO" "Deneme $attempt/$MAX_RETRY başlıyor: $SOURCE -> $DEST"

    rsync -avz 
        --delete 
        --stats 
        --log-file="$LOG_FILE" 
        --log-file-format="%t [%i] %n (%b bytes)" 
        --timeout=300 
        --partial 
        --partial-dir=".rsync-partial" 
        -e "ssh -o ConnectTimeout=30 -o ServerAliveInterval=60 -o BatchMode=yes" 
        --exclude='*.tmp' --exclude='*.swp' --exclude='.git/' 
        "$SOURCE" "$DEST"

    EXIT_CODE=$?

    if [ $EXIT_CODE -eq 0 ] || [ $EXIT_CODE -eq 24 ]; then
        log "INFO" "${GREEN}Yedekleme başarılı (kod: $EXIT_CODE)${NC}"
        break
    elif [ $EXIT_CODE -eq 23 ]; then
        log "WARN" "${YELLOW}Kısmi başarı (kod 23) - bazı dosyalar atlandı${NC}"
        break
    else
        log "ERROR" "${RED}Deneme $attempt başarısız (kod: $EXIT_CODE)${NC}"
        if [ $attempt -lt $MAX_RETRY ]; then
            log "INFO" "$RETRY_DELAY saniye beklenip tekrar denenecek"
            sleep $RETRY_DELAY
        fi
    fi
done

# Sonuç raporu
if [ $EXIT_CODE -ne 0 ] && [ $EXIT_CODE -ne 23 ] && [ $EXIT_CODE -ne 24 ]; then
    log "ERROR" "Tüm denemeler başarısız oldu!"
    mail -s "[ALARM] Yedekleme Başarısız: $JOB_NAME @ $(hostname)" 
        "$MAIL_TO" < "$LOG_FILE"
    exit 1
fi

# Eski logları temizle
find "$LOG_DIR" -name "${JOB_NAME}_*.log" -mtime +30 -delete
log "INFO" "30 günden eski loglar temizlendi"

exit 0

Logrotate ile Log Yönetimi

Rsync logları zamanla büyüyebilir. Logrotate ile otomatik yönetim:

# /etc/logrotate.d/rsync
/var/log/rsync/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
    dateext
    dateformat -%Y%m%d
    postrotate
        # Eğer rsyncd daemon çalışıyorsa HUP gönder
        if [ -f /var/run/rsyncd.pid ]; then
            kill -HUP $(cat /var/run/rsyncd.pid) 2>/dev/null || true
        fi
    endscript
}

/var/log/rsync/summary.log {
    weekly
    rotate 12
    compress
    delaycompress
    missingok
    notifempty
}

Log Analizi ve İzleme

Biriken loglardan anlamlı bilgi çıkarmak için bazı pratik komutlar:

# Son 7 günün başarı/başarısızlık oranı
grep -E "(başarılı|HATA|başarısız)" /var/log/rsync/summary.log | 
    tail -n 50 | 
    awk '{print $1, $2, $NF}' | 
    column -t

# Transfer edilen toplam veri miktarı
grep "Total transferred file size" /var/log/rsync/backup_*.log | 
    awk '{print $NF}' | 
    awk '{sum += $1} END {print "Toplam: " sum/1024/1024 " MB"}'

# En sık atlanan dosyalar (hatalı transferler)
grep "cannot" /var/log/rsync/backup_*.log | 
    awk '{print $NF}' | sort | uniq -c | sort -rn | head -10

# Yavaş transferleri tespit et (30 dakikadan uzun sürenler)
awk '/başlıyor/{start=$1} /başarılı/{
    end=$1
    diff = end - start
    if (diff > 1800) print "Yavaş transfer: " diff " saniye"
}' /var/log/rsync/summary.log

# Belirli bir tarihteki tüm hatalar
grep "2024-01-15" /var/log/rsync/backup_*.log | grep -i "error|fail|cannot"

Systemd Journal ile Entegrasyon

Modern Linux sistemlerinde rsync işlemlerini systemd service olarak tanımlamak log yönetimini kolaylaştırır:

# /etc/systemd/system/rsync-backup.service
[Unit]
Description=Rsync Yedekleme Servisi
After=network.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/smart-backup.sh /data [email protected]:/backup web_backup
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rsync-backup

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/rsync-backup.timer
[Unit]
Description=Gece 02:00 Rsync Yedekleme
Requires=rsync-backup.service

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

[Install]
WantedBy=timers.target
# Servisi etkinleştir
systemctl daemon-reload
systemctl enable rsync-backup.timer
systemctl start rsync-backup.timer

# Journal'dan logları izle
journalctl -u rsync-backup.service -f
journalctl -u rsync-backup.service --since "2024-01-01" --until "2024-01-31"

# Sadece hataları göster
journalctl -u rsync-backup.service -p err

Checksums ile Veri Bütünlüğü Doğrulama

Yedeklemenin doğru yapıldığından emin olmak için checksum doğrulaması:

# Checksum bazlı karşılaştırma (daha yavaş ama güvenilir)
rsync -avz --checksum 
    --log-file=/var/log/rsync/checksum_verify.log 
    /data/critical/ [email protected]:/backup/critical/

# Yedekleme sonrası doğrulama scripti
#!/bin/bash
SOURCE="/data/critical"
DEST="[email protected]:/backup/critical"
DIFF_LOG="/var/log/rsync/integrity_check_$(date +%Y%m%d).log"

echo "Bütünlük kontrolü başlıyor: $(date)" > "$DIFF_LOG"

# Dry-run ile checksum karşılaştırması
rsync -avzn --checksum 
    --out-format="FARK: %n (kaynak: %l bytes)" 
    "$SOURCE/" "$DEST/" >> "$DIFF_LOG" 2>&1

DIFF_COUNT=$(grep -c "^FARK:" "$DIFF_LOG" || true)

if [ "$DIFF_COUNT" -gt 0 ]; then
    echo "UYARI: $DIFF_COUNT dosyada tutarsızlık tespit edildi!" | tee -a "$DIFF_LOG"
    mail -s "Yedekleme Bütünlük Uyarısı: $DIFF_COUNT dosya farklı" [email protected] < "$DIFF_LOG"
else
    echo "OK: Tüm dosyalar tutarlı" | tee -a "$DIFF_LOG"
fi

Sonuç

Rsync hata ayıklama ve log yönetimi, “çalışıyor mu çalışmıyor mu” sorusundan çok ötede bir konu. İyi yapılandırılmış bir log sistemi sana şunu sağlar: bir sorun çıktığında saatlerce uğraşmak yerine dakikalar içinde neyin yanlış gittiğini anlayabilirsin.

En önemli çıkarımları özetleyecek olursam:

  • Çıkış kodlarını her zaman kontrol et, özellikle 23 ve 24 kodlarına özel muamele yap
  • --itemize-changes ve --stats seçeneklerini production loglarına dahil et, fazladan yer kaplar ama sorun anında altın değeri taşır
  • Retry mekanizması olmayan bir yedekleme scripti eksik bir scripttir, geçici ağ sorunları için mutlaka ekle
  • Log dosyalarını logrotate ile yönet, disk dolup sunucu durmasın
  • Systemd timer ile cron yerine modern yedekleme zamanlaması kullan, journal entegrasyonu sayesinde merkezi log yönetimi kolaylaşır
  • Düzenli bütünlük kontrolleri yap, “yedekleme var” demek “yedekleme çalışıyor ve veri tutarlı” demek değildir

Bu konuyu bir kez doğru kurarsın, sonrasında yedekleme sistemi seni değil, sen yedekleme sistemini yönetirsin.

Bir yanıt yazın

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