MariaDB için Otomatik Yedekleme: mysqldump, Rotasyon ve Geri Yükleme Testi
Her gece çalışan, eski yedekleri temizleyen ve asıl önemlisi geri yüklenebildiği doğrulanan bir MariaDB yedekleme düzeni nasıl kurulur? Betik, systemd timer ve test yöntemi.
Yedekleme konusundaki en pahalı ders şudur: yedeği olan değil, geri yükleyebilen kişi güvendedir. Birçok kurulumda yedek dosyası düzenli olarak oluşur ama bozuktur, boştur veya eksik veri içerir. Fark edilmesi için bir felaket gerekir. Bu yazıda MariaDB için basit ama sağlam bir düzen kuracağız.
Mantıksal yedek nedir?
mysqldump (MariaDB'de mariadb-dump ismiyle de bulunur) veritabanını, yeniden oluşturan SQL komutları olarak dışa aktarır. Küçük ve orta ölçekli veritabanları (birkaç GB'a kadar) için en pratik yöntemdir. Çıktı bir metin dosyasıdır; sıkıştırılır, başka makineye kopyalanır, sürümler arası taşınabilir.
Çok büyük veritabanlarında veya saniye bazında kurtarma gerektiğinde fiziksel yedek (mariabackup) ve binlog tabanlı noktaya geri dönüş gerekir. Bu yazının kapsamı dışındadır.
1. Yedek için ayrı, kısıtlı bir kullanıcı
Yedeği root ile almak gereksiz risktir. Yalnızca okuma yetkisi olan bir kullanıcı oluşturun:
CREATE USER 'yedek'@'localhost' IDENTIFIED BY 'guclu-bir-parola';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON uygulama_db.* TO 'yedek'@'localhost';
FLUSH PRIVILEGES;
Parolayı komut satırına yazmak yerine ~/.my.cnf içinde tutun ve izni kısıtlayın:
[client]
user=yedek
password=guclu-bir-parola
chmod 600 ~/.my.cnf
Komut satırına yazılan parola ps çıktısında diğer kullanıcılara görünür; bu dosya yöntemi bunu engeller.
2. Yedekleme betiği
/usr/local/bin/db-yedek.sh:
#!/usr/bin/env bash
set -euo pipefail
DB="uygulama_db"
DIZIN="$HOME/yedekler"
TARIH="$(date +%Y%m%d_%H%M%S)"
DOSYA="$DIZIN/${DB}_${TARIH}.sql.gz"
SAKLA_GUN=14
mkdir -p "$DIZIN"
# --single-transaction: InnoDB tablolarını kilitlemeden tutarlı kopya alır
mariadb-dump --single-transaction --routines --events "$DB" | gzip -9 > "$DOSYA.gecici"
# Dosya sıkıştırma açısından sağlam mı?
gzip -t "$DOSYA.gecici"
mv "$DOSYA.gecici" "$DOSYA"
# Eski yedekleri sil
find "$DIZIN" -name "${DB}_*.sql.gz" -mtime +"$SAKLA_GUN" -delete
echo "TAMAM: $DOSYA ($(du -h "$DOSYA" | cut -f1))"
Dikkat edilecek noktalar:
set -euo pipefailsayesinde herhangi bir adım hata verirse betik durur.pipefailolmadanmariadb-dumpçökse bilegzipbaşarılı döner ve boş bir yedek "başarılı" görünür.- Dosya önce
.geciciadıyla yazılır, test edilir, sonra asıl adına taşınır. Yarım kalmış bir dosya yedek gibi görünmez. --single-transactionyalnızca InnoDB tablolarında tutarlılık sağlar. MyISAM tabloları varsa kilitleme gerekir.
sudo chmod +x /usr/local/bin/db-yedek.sh
3. systemd timer ile zamanlama
/etc/systemd/system/db-yedek.service:
[Unit]
Description=Veritabani yedegi
[Service]
Type=oneshot
User=pi
ExecStart=/usr/local/bin/db-yedek.sh
/etc/systemd/system/db-yedek.timer:
[Unit]
Description=Her gece veritabani yedegi
[Timer]
OnCalendar=*-*-* 03:15:00
Persistent=true
RandomizedDelaySec=120
[Install]
WantedBy=timers.target
Persistent=true, cihaz o saatte kapalıysa açıldığında kaçırılan çalıştırmayı telafi eder. Cron'da bu yoktur. Etkinleştirin:
sudo systemctl daemon-reload
sudo systemctl enable --now db-yedek.timer
systemctl list-timers db-yedek.timer
İlk denemeyi beklemeden sudo systemctl start db-yedek.service ile yapın ve journalctl -u db-yedek ile sonucu görün.
4. Yedeği başka yere kopyalayın
Yedek, veritabanıyla aynı diskte duruyorsa disk bozulduğunda ikisi birlikte gider. En az bir kopyayı başka bir cihaza taşıyın. rsync ile SSH üzerinden:
rsync -a --delete-after "$HOME/yedekler/" kullanici@baska-makine:/yedekler/uygulama/
Bu konunun mantığı 3-2-1 yedekleme kuralı yazımızda anlatılıyor.
5. Geri yükleme testi: asıl önemli adım
Ayda bir, yedeği ayrı bir test veritabanına yükleyip kayıt sayısına bakın:
mariadb -e "CREATE DATABASE IF NOT EXISTS test_geri_yukle"
gunzip -c ~/yedekler/uygulama_db_20261004_031500.sql.gz | mariadb test_geri_yukle
mariadb -e "SELECT COUNT(*) FROM test_geri_yukle.hareket"
mariadb -e "DROP DATABASE test_geri_yukle"
Sayı üretimdeki tabloyla (yedek saatine göre) tutarlıysa yedeğiniz gerçektir. Bu testi takvime yazın; "yaparım" demek yetmez.
Kontrol listesi
- Yedek kullanıcısı yalnızca gerekli yetkilere sahip.
- Parola
~/.my.cnfiçinde ve izni 600. pipefailaçık, geçici dosya adı kullanılıyor.- Timer
Persistent=true. - Bir kopya başka cihazda.
- Geri yükleme testi takvimde.
- Yedekte kişisel veri varsa saklama süresi ve erişim yetkisi belirlenmiş (bkz. KVKK yazımız).
Yedeğin boyutunu ve süresini anlamak
Mantıksal döküm, veritabanının SQL metnidir; boyutu veriden büyüktür ama sıkıştırınca (gzip) genellikle %10–25'e iner. Bir personel paneli gibi metin ağırlıklı tablolarda birkaç yüz bin satırlık bir veri, sıkıştırılmış birkaç megabayt tutar. Süre ise tabloların büyüklüğüne ve Pi'nin disk hızına bağlıdır; SD kartlı bir Pi 3'te yüzbinlerce satır birkaç saniye ile bir dakika arasında sürer. Dökümün çalıştığı sırada kullanıcıların etkilenmemesi için --single-transaction seçeneği InnoDB tablolarında tutarlı bir anlık görüntü alır ve tabloları kilitlemez. Saklama süresine göre ne kadar diskte yer gerektiğini yedek alanı hesaplayıcı ile bulabilirsiniz.
Yedeğin sağlamlığını otomatik kontrol etmek
Dosyanın oluşması yeterli değildir. Betiğin sonuna üç kontrol ekleyin:
- Çıkış kodu:
mysqldumphata verdiyse dosya yarım olabilir; betikset -euo pipefailile hatada durmalı. - Boyut: Yeni dosya, bir öncekinin yarısından küçükse bir sorun vardır (disk dolmuş olabilir). Alarm üretin.
- Bütünlük:
gzip -t dosya.sql.gzile sıkıştırmanın bozuk olmadığını doğrulayın; ardından başlığındaDump completedsatırının bulunduğuna bakın.
Bunların hiçbiri sessiz kalmamalı; bir hatayı e-posta ya da bildirimle haber verin (servis izleme ve alarm). Gerçek bir sistemde yarım kalmış bir haftalık kopyayı ancak geri yükleme denemesinde fark etmiştik (yedek tatbikatı notu); bütünlük kontrolü bu yüzden betikte zorunlu.
Sık karşılaşılan hatalar
- Parolayı komut satırına yazmak. Parola
psçıktısında görünür. Bunun yerine yalnızca yedek kullanıcısına ait,600izinli bir seçenek dosyası kullanın. - Root ile yedek almak. Yedek kullanıcısına yalnızca
SELECT,LOCK TABLES,SHOW VIEW,EVENTveTRIGGERyetkileri verin. - Karakter kümesi uyuşmazlığı. Türkçe karakterlerin bozulmaması için dökümde ve geri yüklemede
utf8mb4kullanıldığından emin olun. - Rutinleri unutmak. Saklı yordamlar ve tetikleyiciler için
--routines --triggersekleyin. - Yedeği aynı diskte bırakmak. Disk giderse hepsi gider; en az bir kopya başka bir cihaza gitmeli (rsync ile uzak yedek).
- Zamanlayıcının çalışmadığını fark etmemek.
systemctl list-timersile son çalışmayı düzenli kontrol edin (timer ve cron).
Sık sorulan sorular
Mantıksal yedek mi, fiziksel yedek mi? Küçük ve orta ölçekli veritabanları için mantıksal döküm yeterli ve taşınabilirdir. Çok büyük veritabanlarında fiziksel yedek araçları daha hızlıdır ama kurulumu karmaşıktır.
Yedek alırken uygulamayı durdurmam gerekir mi? --single-transaction ile InnoDB tablolarında gerekmez. MyISAM tablolarında kilit gerekebilir.
Geri yüklemeyi nerede denemeliyim? Canlı veritabanının üzerine değil, ayrı bir test veritabanına yükleyin ve satır sayılarını canlıyla karşılaştırın.
Yedeği şifrelemeli miyim? Uzak bir yere gidiyorsa evet; personel verisi gibi kişisel veri içeren dökümler şifresiz taşınmamalı (KVKK notları).