MariaDB Veritabanı Yedekleme ve Geri Yükleme
Veritabanı yedeklemesi konusunda yıllarca “zaten bulut ortamında, bir şey olmaz” diyip sonunda gece 2’de panikleyen sysadmin’lerin çığlığını çok duydum. MariaDB’yi doğru yedeklemek sandığından çok daha fazla nüans içeriyor; sıradan bir mysqldump çalıştırmak yeterli değil, ne zaman, nasıl, ne kadarını ve nasıl geri döneceğini de bilmen gerekiyor.
Neden Yedekleme Stratejisi Önemli?
Şunu hemen söyleyeyim: yedek almak ile kullanılabilir yedek almak birbirinden tamamen farklı kavramlar. Yıllarca aldığın yedeği test etmeden saklamak, bir yangın tatbikatını hiç yapmadan yangın tüplerini doldurmak gibi. Gerçekten ihtiyacın olduğu an, o yedeğin işe yarayıp yaramadığını öğrenirsin.
MariaDB için konuşacak olursak, temel olarak üç farklı yedekleme yaklaşımı var:
- Mantıksal yedekleme (Logical Backup):
mysqldumpveyamariadb-dumpile SQL formatında dışa aktarma - Fiziksel yedekleme (Physical Backup): Veri dosyalarının doğrudan kopyalanması,
Mariabackupile hot backup - Binary log tabanlı yedekleme: Point-in-time recovery için binary log’ların saklanması
Her birinin yeri var, ama hangi senaryoda hangisini kullanacağını bilmek kritik.
mysqldump ile Temel Yedekleme
En çok bilinen, en çok kullanılan ve maalesef en çok yanlış kullanılan araç. mysqldump mantıksal yedekleme yapar, yani verini SQL komutlarına dönüştürür. Küçük ve orta ölçekli veritabanları için gayet iyi çalışır.
Tek Bir Veritabanını Yedekleme
mysqldump -u root -p --single-transaction --routines --triggers --events mydb > /backup/mydb_$(date +%Y%m%d_%H%M%S).sql
Buradaki parametrelere dikkat et:
- –single-transaction: InnoDB tablolar için tutarlı bir snapshot alır, tabloları kilitlemez. Üretim ortamında mutlaka bu flag’i kullan.
- –routines: Stored procedure ve function’ları dahil eder.
- –triggers: Trigger’ları dahil eder.
- –events: Event Scheduler event’lerini dahil eder.
Eğer --single-transaction kullanmadan yedek alırsan ve InnoDB tablo kullanıyorsan, tutarsız bir yedek alabilirsin. Bunu öğrenmek için genellikle bir production olayı yaşamak gerekiyor, ama şanslısın ki şimdi okudun.
Tüm Veritabanlarını Yedekleme
mysqldump -u root -p
--all-databases
--single-transaction
--routines
--triggers
--events
--master-data=2
--flush-logs
| gzip > /backup/full_backup_$(date +%Y%m%d_%H%M%S).sql.gz
- –all-databases: Tüm veritabanlarını, sistem tablolarını da dahil ederek alır.
- –master-data=2: Yorum satırı olarak binary log pozisyonunu ekler. Replikasyon kurulumunda veya point-in-time recovery’de altın değerinde.
- –flush-logs: Yedekleme başlamadan önce binary log’u rotate eder.
MyISAM Tablolar İçin Dikkat
MyISAM hala kullanan ortamlar var (özellikle eski uygulamalar). Bu tablolar için --single-transaction işe yaramaz, tablo kilidi gerekir:
mysqldump -u root -p
--lock-all-tables
--routines
--triggers
mydb_with_myisam > /backup/myisam_db_$(date +%Y%m%d_%H%M%S).sql
--lock-all-tables yedekleme süresince tüm tabloları kilitler. Yüksek trafikli sistemlerde bu ciddi sorun yaratır. Mümkünse InnoDB’ye geçin.
Mariabackup ile Fiziksel Hot Backup
Büyük veritabanlarında mysqldump kullanmak acı verir. 100 GB veritabanını dump etmeye çalışırsan hem çok zaman alır hem de yüksek I/O yükü oluşturur. Bunun için Mariabackup var.
Mariabackup, Percona XtraBackup’ın MariaDB için fork’u. InnoDB tablolar için gerçek anlamda hot backup yapıyor, yani sunucu çalışmaya devam ederken veri dosyalarını kopyalayabiliyor.
Kurulum
# RHEL/CentOS/Rocky Linux
dnf install MariaDB-backup
# Debian/Ubuntu
apt install mariadb-backup
Full Backup Alma
mariabackup --backup
--target-dir=/backup/full_$(date +%Y%m%d)
--user=root
--password=your_password
Yedek tamamlandığında henüz restore edilebilir durumda değil. Prepare adımı şart:
mariabackup --prepare
--target-dir=/backup/full_20240115
Prepare adımı InnoDB’nin crash recovery mekanizmasını çalıştırarak yedeği tutarlı hale getirir. Bu adımı atlarsan restore ettiğinde MariaDB başlamayacak.
Artımlı (Incremental) Yedekleme
Büyük ortamlarda her gece full backup almak hem disk hem de zaman israfı. Artımlı yedekleme ile sadece değişen sayfaları yedekleyebilirsin:
# Önce full backup
mariabackup --backup
--target-dir=/backup/full_base
--user=root
--password=your_password
# Sonraki günlerde artımlı
mariabackup --backup
--target-dir=/backup/inc_$(date +%Y%m%d)
--incremental-basedir=/backup/full_base
--user=root
--password=your_password
Restore ederken sırayla prepare etmen gerekiyor:
# Önce full backup'ı prepare et (--apply-log-only önemli!)
mariabackup --prepare
--apply-log-only
--target-dir=/backup/full_base
# Artımlı backup'ları sırayla uygula
mariabackup --prepare
--apply-log-only
--target-dir=/backup/full_base
--incremental-dir=/backup/inc_20240116
# Son artımlı backup için --apply-log-only kullanma
mariabackup --prepare
--target-dir=/backup/full_base
--incremental-dir=/backup/inc_20240117
--apply-log-only flag’ini son adım dışında kullanman kritik. Son adımda kullanırsan sonraki artımlı backup’ı uygulayamazsın.
Binary Log ile Point-in-Time Recovery
Şimdi işin gerçekten kritik kısmına geliyoruz. Diyelim ki sabah 09:00’da full backup aldın. Öğleden sonra 14:30’da bir geliştirici “yanlışlıkla” production veritabanındaki müşteri tablosunu sildi. Full backup’a dönersin, 09:00’dan 14:29’a kadar olan işlemleri kaybedersin. Point-in-time recovery bunu çözüyor.
Binary Log Aktifleştirme
/etc/mysql/mariadb.conf.d/50-server.cnf veya /etc/my.cnf.d/server.cnf dosyasına ekle:
[mysqld]
log_bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 100M
server_id = 1
Değişiklik sonrası restart:
systemctl restart mariadb
Binary log aktif mi kontrol:
mysql -u root -p -e "SHOW VARIABLES LIKE 'log_bin';"
mysql -u root -p -e "SHOW BINARY LOGS;"
Point-in-Time Recovery Senaryosu
Gerçek bir senaryo üzerinden gidelim. Sabah 08:00’da full backup aldın, öğle 13:45’te yanlış bir DELETE çalıştı.
Önce full backup’ı restore et, sonra binary log’ları belirli bir noktaya kadar uygula:
# Binary log içeriğini incele
mysqlbinlog /var/log/mysql/mysql-bin.000023 | grep -A 5 "DELETE FROM customers"
# Belirli bir zamana kadar binary log uygula
mysqlbinlog
--start-datetime="2024-01-15 08:00:00"
--stop-datetime="2024-01-15 13:44:59"
/var/log/mysql/mysql-bin.000023
/var/log/mysql/mysql-bin.000024
| mysql -u root -p mydb
Ya da timestamp yerine binary log pozisyonunu kullanabilirsin (daha kesin):
# Pozisyona göre uygula
mysqlbinlog
--start-position=4
--stop-position=38457291
/var/log/mysql/mysql-bin.000023
| mysql -u root -p mydb
Geri Yükleme Prosedürleri
Yedek almak kadar geri yüklemeyi de bilmek gerekiyor. Stres altında, gece yarısı, telefon çalarken doğru adımları izleyebilmen için bunları önceden prova etmiş olman lazım.
mysqldump Yedeğinden Geri Yükleme
# Sıkıştırılmış yedek
gunzip < /backup/mydb_20240115_080000.sql.gz | mysql -u root -p mydb
# Normal SQL dosyası
mysql -u root -p mydb < /backup/mydb_20240115_080000.sql
# Tüm veritabanları yedeği
mysql -u root -p < /backup/full_backup_20240115_080000.sql
Büyük yedeklerde geri yükleme işlemini hızlandırmak için:
mysql -u root -p << 'EOF'
SET GLOBAL innodb_flush_log_at_trx_commit = 0;
SET GLOBAL sync_binlog = 0;
EOF
mysql -u root -p mydb < /backup/large_backup.sql
mysql -u root -p << 'EOF'
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
SET GLOBAL sync_binlog = 1;
EOF
Bu ayarları sadece restore süresince değiştir, sonra mutlaka geri al. Aksi halde crash durumunda veri kaybı riski taşırsın.
Mariabackup’tan Geri Yükleme
# MariaDB servisini durdur
systemctl stop mariadb
# Mevcut veri dizinini temizle (ya da taşı)
mv /var/lib/mysql /var/lib/mysql_old
# Yedeği restore et
mariabackup --copy-back
--target-dir=/backup/full_base
# İzinleri düzelt
chown -R mysql:mysql /var/lib/mysql
# Servisi başlat
systemctl start mariadb
--copy-back yerine --move-back kullanırsan yedek dizinindeki dosyalar taşınır, kopyalanmaz. Disk alanı sıkışıksa işe yarar ama sonra o backup kullanılamaz hale gelir.
Otomatik Yedekleme Script’i
Production ortamında manuel yedek almak olmaz. İşte kullandığım, zaman içinde olgunlaşmış bir bash script’i:
#!/bin/bash
# MariaDB Otomatik Yedekleme Script'i
# /usr/local/bin/mariadb_backup.sh
set -euo pipefail
### Konfigürasyon
BACKUP_DIR="/backup/mariadb"
DB_USER="backup_user"
DB_PASS="güçlü_şifre_buraya"
RETENTION_DAYS=7
LOG_FILE="/var/log/mariadb_backup.log"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="${BACKUP_DIR}/${TIMESTAMP}"
### Log fonksiyonu
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
### Hata yakalama
error_exit() {
log "HATA: $1"
# Buraya alert göndermek için entegrasyon eklenebilir
exit 1
}
### Backup dizini oluştur
mkdir -p "$BACKUP_PATH" || error_exit "Backup dizini oluşturulamadı"
log "Yedekleme başlıyor: $TIMESTAMP"
### Veritabanı listesini al (sistem DB'leri hariç)
DATABASES=$(mysql -u "$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" 2>/dev/null |
grep -Ev "(Database|information_schema|performance_schema|sys)")
### Her veritabanını ayrı yedekle
for DB in $DATABASES; do
log "Yedekleniyor: $DB"
mysqldump -u "$DB_USER" -p"$DB_PASS"
--single-transaction
--routines
--triggers
--events
--flush-logs
"$DB" 2>>"$LOG_FILE" |
gzip > "${BACKUP_PATH}/${DB}.sql.gz" ||
error_exit "$DB yedeklenemedi"
log "$DB tamamlandı: $(du -sh "${BACKUP_PATH}/${DB}.sql.gz" | cut -f1)"
done
### Eski yedekleri temizle
log "Eski yedekler temizleniyor (${RETENTION_DAYS} günden eski)"
find "$BACKUP_DIR" -maxdepth 1 -type d -mtime "+${RETENTION_DAYS}" -exec rm -rf {} ; 2>>"$LOG_FILE"
log "Yedekleme tamamlandı. Toplam boyut: $(du -sh "$BACKUP_PATH" | cut -f1)"
Script’i cron’a ekle:
# Her gün gece 02:00'de çalıştır
0 2 * * * /usr/local/bin/mariadb_backup.sh
Yedekleme Kullanıcısı Oluşturma
Root ile yedek almak kötü bir pratik. Minimum yetkili bir yedekleme kullanıcısı oluştur:
mysql -u root -p << 'EOF'
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'güçlü_şifre';
GRANT SELECT, RELOAD, LOCK TABLES, REPLICATION CLIENT, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EOF
Mariabackup için biraz daha fazla yetki gerekiyor:
mysql -u root -p << 'EOF'
GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup_user'@'localhost';
GRANT BACKUP_ADMIN ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;
EOF
Yedek Bütünlüğü Doğrulama
Aldığın yedeğin gerçekten işe yarayıp yaramadığını test etmeden bilemezsin. Bunu otomatize etmek için bir doğrulama script’i kullanabilirsin:
#!/bin/bash
# Yedek doğrulama - test ortamında çalıştır
BACKUP_FILE=$1
TEST_DB="backup_verify_$(date +%s)"
if [ -z "$BACKUP_FILE" ]; then
echo "Kullanım: $0 /backup/mydb_20240115.sql.gz"
exit 1
fi
echo "Test veritabanı oluşturuluyor: $TEST_DB"
mysql -u root -p -e "CREATE DATABASE $TEST_DB;"
echo "Yedek yükleniyor..."
gunzip < "$BACKUP_FILE" | mysql -u root -p "$TEST_DB"
if [ $? -eq 0 ]; then
echo "BAŞARILI: Yedek başarıyla yüklendi"
# Tablo sayısını kontrol et
TABLE_COUNT=$(mysql -u root -p -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$TEST_DB';" -s -N)
echo "Tablo sayısı: $TABLE_COUNT"
else
echo "HATA: Yedek yüklenemedi!"
fi
# Test veritabanını temizle
mysql -u root -p -e "DROP DATABASE $TEST_DB;"
echo "Test veritabanı silindi"
Replikasyon Ortamında Yedekleme
Replikasyon kurulumu varsa yedekleri master yerine slave üzerinden almak çok daha akıllıca. Bu şekilde master’a hiç yük bindirmezsin.
# Slave üzerinde yedek alırken replikasyonu geçici durdur
mysql -u root -p -e "STOP SLAVE SQL_THREAD;"
mysqldump -u backup_user -p
--single-transaction
--master-data=2
--all-databases
| gzip > /backup/slave_backup_$(date +%Y%m%d).sql.gz
mysql -u root -p -e "START SLAVE SQL_THREAD;"
--master-data=2 yerine --dump-slave=2 kullanmayı da tercih edebilirsin; bu parametre slave’in binary log pozisyonunu değil, master’ın pozisyonunu yedek dosyasına yazar. Replikasyonu sıfırdan kurarken işe yarar.
Sık Karşılaşılan Sorunlar ve Çözümleri
Yedekleme yaparken karşılaştığım ve sıkça gördüğüm sorunları da paylaşayım.
“Access denied for user” hatası: Yedekleme kullanıcısının yeterli yetkisi yok. Özellikle --events parametresi ile yedek alırken EVENT yetkisi gerektiğini unutma.
Büyük blob alanlarında timeout: --max-allowed-packet değerini artır:
mysqldump -u root -p
--max-allowed-packet=512M
--single-transaction
mydb > /backup/mydb.sql
“Got error: 1044” veya yedek bozuk çıkıyor: Yedekleme sırasında veritabanı değişiyor olabilir. --single-transaction kullandığından emin ol. Bozuk yedekleri kontrol etmek için:
# Sıkıştırılmış yedeğin bütünlüğünü kontrol et
gunzip -t /backup/mydb_20240115.sql.gz && echo "Dosya sağlam" || echo "Dosya bozuk!"
Disk doldu, yedek yarım kaldı: Yedekleme öncesi disk kontrolü:
AVAILABLE=$(df /backup --output=avail -k | tail -1)
DBSIZE=$(mysql -u root -p -e "SELECT SUM(data_length + index_length) FROM information_schema.tables;" -s -N)
REQUIRED=$((DBSIZE * 2)) # 2x güvenlik payı
if [ "$AVAILABLE" -lt "$REQUIRED" ]; then
echo "Yeterli disk alanı yok! Mevcut: ${AVAILABLE}K, Gereken: ${REQUIRED}K"
exit 1
fi
Bulut Ortamında Yedekleme Senaryoları
Yedeği sadece local’de tutmak yetmez. Sunucun kendisi giderse yedeğin de gider. En azından bir uzak konuma kopyalamak şart.
# S3 uyumlu depolama alanına yükleme (MinIO, AWS S3, Cloudflare R2)
aws s3 cp /backup/mydb_20240115_080000.sql.gz
s3://my-backup-bucket/mariadb/$(date +%Y/%m/%d)/
--storage-class STANDARD_IA
# rsync ile uzak sunucuya kopyalama
rsync -avz --delete
/backup/mariadb/
backup-server:/mnt/backup/mariadb/
# rclone ile farklı cloud provider'lara
rclone copy /backup/mariadb/
myremote:backup-bucket/mariadb/
--min-age 1h
--log-level INFO
Yedekleri şifreleyerek saklamak da önemli. Müşteri verisi içeren bir yedeğin şifresiz S3’te durması KVKK ve GDPR açısından ciddi risk:
# GPG ile şifrele
mysqldump -u root -p mydb |
gzip |
gpg --cipher-algo AES256 --compress-algo 0
--passphrase-file /etc/backup/gpg_passphrase
--batch -c - > /backup/mydb_$(date +%Y%m%d).sql.gz.gpg
# Geri yüklemek için
gpg --passphrase-file /etc/backup/gpg_passphrase
--batch -d /backup/mydb_20240115.sql.gz.gpg |
gunzip | mysql -u root -p mydb
Sonuç
MariaDB yedekleme stratejisi tek bir araçla veya tek bir yöntemle tamamlanmaz. İyi bir strateji birden fazla katmandan oluşur: düzenli mysqldump veya Mariabackup ile tam yedekler, binary log ile point-in-time recovery kapasitesi, uzak konuma kopyalama ve düzenli geri yükleme testleri.
En kritik nokta şu: aldığın yedeği test etmeden değeri yok. Ayda en az bir kere test ortamına geri yükleme yaparak yedeğin çalıştığını doğrula. Gerçek bir kriz anında ilk defa restore prosedürünü test etmek hem sana hem de şirketine çok pahalıya mal olabilir.
Binary log’u mutlaka aktif et, özellikle üretim ortamlarında. Disk maliyeti yok denecek kadar az, ama sağladığı esneklik paha biçilemez. “Yanlışlıkla silinen” bir tabloyu binary log olmadan kurtarman neredeyse imkansız; binary log ile ise birkaç dakika içinde çözebilirsin.
Son bir not: yedekleme scriptlerini ve prosedürlerini dokümante et ve ekibinle paylaş. Gece 3’te sen yokken bir şey olursa, başka birinin bu prosedürleri uygulayabilmesi gerekebilir. “Kafamda var” diyerek güvende olmak seni değil, sadece seni rahatlatır.
