Veritabanı yönetiminde en kritik konulardan biri yüksek erişilebilirlik ve veri güvenliğidir. Tek bir MySQL sunucusuyla çalışırken disk arızası, donanım sorunu veya yazılım hataları veri kaybına yol açabilir. İşte tam bu noktada replikasyon devreye giriyor. MySQL replikasyonu, bir sunucudaki verilerin otomatik olarak başka bir sunucuya kopyalanmasını sağlar. Bu yazıda Master-Slave replikasyonunu sıfırdan kuracağız, yaygın hataları inceleyeceğiz ve production ortamında karşılaşabileceğiniz gerçek senaryolara bakacağız.
MySQL Replikasyonu Nedir ve Neden Gerekli?
MySQL replikasyonu, bir veritabanı sunucusundaki (master) değişikliklerin otomatik olarak bir veya birden fazla sunucuya (slave) aktarılması işlemidir. Bu işlem binary log mekanizması üzerinden yürür. Master sunucu her veri değişikliğini binary log’a yazar, slave sunucu bu log’ları okuyarak kendi üzerinde aynı işlemleri tekrarlar.
Replikasyonun sağladığı avantajlar şunlardır:
- Yüksek erişilebilirlik: Master çöktüğünde slave devreye alınabilir
- Okuma yükü dağılımı: SELECT sorguları slave’lere yönlendirilerek master üzerindeki yük azaltılır
- Yedekleme: Slave üzerinde production’ı etkilemeden yedek alınabilir
- Coğrafi dağıtım: Farklı lokasyonlarda veri kopyaları tutulabilir
- Raporlama: Ağır analitik sorgular slave üzerinde çalıştırılabilir
Ortam Hazırlığı
Bu kurulum için iki ayrı sunucu kullanacağız:
- Master: 192.168.1.100 (Ubuntu 22.04)
- Slave: 192.168.1.101 (Ubuntu 22.04)
Her iki sunucuda da MySQL 8.0 kurulu olduğunu varsayıyoruz. Kurulu değilse önce kuralım:
# Her iki sunucuda da çalıştırın
sudo apt update
sudo apt install mysql-server -y
sudo systemctl enable mysql
sudo systemctl start mysql
sudo mysql_secure_installation
Sunucular arasındaki bağlantıyı test edin. Slave’den master’a 3306 portuna erişim sağlanabilmesi gerekir:
# Slave sunucusundan çalıştırın
telnet 192.168.1.100 3306
# ya da
nc -zv 192.168.1.100 3306
Eğer bağlantı başarısız oluyorsa firewall kurallarını kontrol edin:
# Master sunucusunda
sudo ufw allow from 192.168.1.101 to any port 3306
sudo ufw reload
Master Sunucu Yapılandırması
MySQL Konfigürasyon Dosyasını Düzenleme
Master sunucusunda /etc/mysql/mysql.conf.d/mysqld.cnf dosyasını açın:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Aşağıdaki parametreleri [mysqld] bölümüne ekleyin veya düzenleyin:
[mysqld]
# Sunucuya benzersiz bir ID verin, her sunucu farklı olmalı
server-id = 1
# Binary log'u aktif edin
log_bin = /var/log/mysql/mysql-bin.log
# Binary log formatı (ROW önerilir)
binlog_format = ROW
# Binary log'ların tutulacağı süre (gün)
expire_logs_days = 7
# Hangi veritabanının replike edileceği (opsiyonel)
binlog_do_db = production_db
# InnoDB kullanıyorsanız bu ayarı aktif edin
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
# Master'ın dinleyeceği IP (0.0.0.0 tüm arayüzler)
bind-address = 0.0.0.0
Değişiklikleri uygulamak için MySQL’i yeniden başlatın:
sudo systemctl restart mysql
sudo systemctl status mysql
Replikasyon Kullanıcısı Oluşturma
Master sunucusunda MySQL’e bağlanın ve slave için özel bir kullanıcı oluşturun:
sudo mysql -u root -p
-- Replikasyon kullanıcısı oluştur
CREATE USER 'replicator'@'192.168.1.101' IDENTIFIED WITH mysql_native_password BY 'GucluBirSifre123!';
-- Replikasyon yetkisi ver
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'192.168.1.101';
-- Yetkileri uygula
FLUSH PRIVILEGES;
-- Kullanıcının oluşturulduğunu doğrula
SELECT user, host FROM mysql.user WHERE user = 'replicator';
Master Durumunu Kaydetme
Bu adım kritik öneme sahiptir. Slave’i yapılandırmadan önce master’ın binary log pozisyonunu not etmemiz gerekiyor:
-- Tabloları kilitleyerek tutarlı bir snapshot alın
FLUSH TABLES WITH READ LOCK;
-- Master durumunu kontrol edin
SHOW MASTER STATUS;
Bu komut çıktısı şuna benzer olacaktır:
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 154 | production_db| |
+------------------+----------+--------------+------------------+
File ve Position değerlerini mutlaka not edin. Bu değerler kurulum boyunca değişmemeli, bu yüzden bu terminali kapatmayın.
Mevcut Veriyi Slave’e Aktarma
Eğer master’da halihazırda veri varsa, önce bu veriyi slave’e aktarmanız gerekir. Yeni bir terminal açın:
# Master'daki veriyi dışa aktarın
mysqldump -u root -p --all-databases --master-data=2 --single-transaction > /tmp/master_dump.sql
# Dump dosyasını slave'e kopyalayın
scp /tmp/master_dump.sql [email protected]:/tmp/
Dump tamamlandıktan sonra master’daki kilidi kaldırın:
-- Master MySQL bağlantısında
UNLOCK TABLES;
Slave Sunucu Yapılandırması
Slave MySQL Konfigürasyonu
Slave sunucusunda /etc/mysql/mysql.conf.d/mysqld.cnf dosyasını düzenleyin:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
# Master'dan farklı bir ID olmalı
server-id = 2
# Slave'de binary log zorunlu değil ama zincir replikasyon için açılabilir
log_bin = /var/log/mysql/mysql-bin.log
# Slave relay log dosyası
relay-log = /var/log/mysql/mysql-relay-bin.log
# Sadece belirli veritabanlarını replike et
replicate_do_db = production_db
# Slave'in read-only olması önerilir
read_only = 1
# Slave loglarını kaydet
log_slave_updates = 1
MySQL’i yeniden başlatın:
sudo systemctl restart mysql
Slave’e Veri Aktarma
Eğer master dump’ı aldıysanız, önce bu veriyi import edin:
sudo mysql -u root -p < /tmp/master_dump.sql
Slave’i Master’a Bağlama
Slave sunucusunda MySQL’e bağlanın:
sudo mysql -u root -p
Master bilgilerini girin. Burada az önce not ettiğiniz File ve Position değerlerini kullanın:
-- Slave durdurulmuşsa emin olun
STOP SLAVE;
-- Master bilgilerini yapılandırın
CHANGE MASTER TO
MASTER_HOST = '192.168.1.100',
MASTER_USER = 'replicator',
MASTER_PASSWORD = 'GucluBirSifre123!',
MASTER_LOG_FILE = 'mysql-bin.000003',
MASTER_LOG_POS = 154;
-- Slave'i başlatın
START SLAVE;
-- Slave durumunu kontrol edin
SHOW SLAVE STATUSG
Replikasyon Durumunu Doğrulama
SHOW SLAVE STATUSG çıktısında dikkat etmeniz gereken kritik alanlar:
- Slave_IO_Running: Yes olmalı
- Slave_SQL_Running: Yes olmalı
- Seconds_Behind_Master: 0 veya düşük bir değer olmalı
- Last_Error: Boş olmalı
Eğer her iki Running değeri de “Yes” ise replikasyon başarıyla kurulmuştur. Test etmek için master’da bir tablo oluşturun ve slave’de görünüp görünmediğini kontrol edin:
-- Master'da çalıştırın
USE production_db;
CREATE TABLE replikasyon_testi (id INT AUTO_INCREMENT PRIMARY KEY, mesaj VARCHAR(255), tarih TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
INSERT INTO replikasyon_testi (mesaj) VALUES ('Replikasyon calisiyor!');
-- Slave'de kontrol edin
USE production_db;
SELECT * FROM replikasyon_testi;
Yaygın Sorunlar ve Çözümleri
Sorun 1: Slave_IO_Running = No
Bu durum genellikle ağ bağlantısı veya kimlik doğrulama sorunlarından kaynaklanır:
-- Master'da kontrol edin
SHOW GRANTS FOR 'replicator'@'192.168.1.101';
-- Slave loglarını inceleyin
sudo tail -f /var/log/mysql/error.log
-- Bağlantı testi
mysql -u replicator -p -h 192.168.1.100
Sorun 2: Slave_SQL_Running = No
Bu durum genellikle master ve slave arasındaki veri tutarsızlığından kaynaklanır:
-- Hata mesajını görün
SHOW SLAVE STATUSG
-- Tek bir hatayı atlamak için (dikkatli kullanın!)
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE;
-- Durumu tekrar kontrol edin
SHOW SLAVE STATUSG
Sorun 3: Slave Geride Kalıyor
Seconds_Behind_Master değeri sürekli artıyorsa performans sorunu var demektir:
-- Slave thread sayısını artırın (MySQL 5.6+)
STOP SLAVE;
SET GLOBAL slave_parallel_workers = 4;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
START SLAVE;
Sorun 4: Binary Log Doldu
# Binary log boyutunu kontrol edin
sudo du -sh /var/log/mysql/
# Eski binary log'ları temizleyin (master'da)
sudo mysql -u root -p -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);"
GTID Tabanlı Replikasyon
MySQL 5.6 ve üzeri sürümlerde GTID (Global Transaction Identifier) kullanmak replikasyon yönetimini büyük ölçüde kolaylaştırır. GTID ile binary log dosyası ve pozisyon takip etmeye gerek kalmaz.
Master ve slave konfigürasyonlarına ekleyin:
# Her iki sunucunun mysqld.cnf dosyasına ekleyin
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
GTID ile slave yapılandırması:
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST = '192.168.1.100',
MASTER_USER = 'replicator',
MASTER_PASSWORD = 'GucluBirSifre123!',
MASTER_AUTO_POSITION = 1;
START SLAVE;
SHOW SLAVE STATUSG
GTID kullanımının avantajları:
- Otomatik pozisyon takibi: Log dosyası ve pozisyon belirtmeye gerek yok
- Güvenilir failover: Slave’leri yeni master’a bağlamak çok daha kolay
- Tutarlılık garantisi: Her transaction benzersiz ID alır, tekrarlama riski yok
Production Ortamında Dikkat Edilecek Noktalar
Slave’i Salt Okunur Yapma
Production ortamında slave sunucularının yanlışlıkla yazılmasını önlemek kritik önem taşır:
-- Geçici olarak
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;
-- Kalıcı olarak mysqld.cnf'e ekleyin
read_only = 1
super_read_only = 1
Replikasyon İzleme
Canlı ortamda replikasyon durumunu düzenli izlemek gerekir. Bunun için basit bir bash scripti yazabilirsiniz:
#!/bin/bash
# /usr/local/bin/check_replication.sh
MYSQL_USER="root"
MYSQL_PASS="sifreniz"
ALERT_THRESHOLD=60 # saniye
STATUS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUSG" 2>/dev/null)
IO_RUNNING=$(echo "$STATUS" | grep "Slave_IO_Running:" | awk '{print $2}')
SQL_RUNNING=$(echo "$STATUS" | grep "Slave_SQL_Running:" | awk '{print $2}')
BEHIND=$(echo "$STATUS" | grep "Seconds_Behind_Master:" | awk '{print $2}')
LAST_ERROR=$(echo "$STATUS" | grep "Last_Error:" | cut -d: -f2-)
if [ "$IO_RUNNING" != "Yes" ] || [ "$SQL_RUNNING" != "Yes" ]; then
echo "KRITIK: Replikasyon durdu! IO: $IO_RUNNING, SQL: $SQL_RUNNING"
echo "Hata: $LAST_ERROR"
# Buraya mail veya Slack bildirimi ekleyin
exit 2
fi
if [ "$BEHIND" -gt "$ALERT_THRESHOLD" ]; then
echo "UYARI: Slave $BEHIND saniye geride!"
exit 1
fi
echo "OK: Replikasyon saglıklı, $BEHIND saniye geride"
exit 0
Bu scripti cron ile düzenli çalıştırın:
chmod +x /usr/local/bin/check_replication.sh
# Her 5 dakikada bir kontrol
echo "*/5 * * * * root /usr/local/bin/check_replication.sh >> /var/log/replication_check.log 2>&1" | sudo tee -a /etc/crontab
Slave Üzerinde Yedek Alma
Replikasyonun en büyük faydalarından biri production’ı etkilemeden yedek alabilmektir:
# Slave'de çalıştırın
# --master-data=2 komutu yorum satırı olarak master pozisyonunu dump'a ekler
mysqldump -u root -p
--all-databases
--single-transaction
--flush-logs
--master-data=2
--routines
--triggers
> /backup/mysql_backup_$(date +%Y%m%d_%H%M%S).sql
# Sıkıştırarak kaydedin
mysqldump -u root -p
--all-databases
--single-transaction
| gzip > /backup/mysql_backup_$(date +%Y%m%d).sql.gz
Failover Senaryosu
Master sunucu çöktüğünde slave’i yeni master olarak devreye almanız gerekir:
# 1. Slave'de tüm relay log'ların işlendiğini bekleyin
SHOW SLAVE STATUSG
# Seconds_Behind_Master = 0 olana kadar bekleyin
# 2. Slave'i durdurun
STOP SLAVE;
# 3. Read-only'yi kaldırın
SET GLOBAL read_only = OFF;
SET GLOBAL super_read_only = OFF;
# 4. Uygulamanızın bağlantı string'ini yeni master IP'sine yönlendirin
# Bu adım uygulamanıza ve load balancer yapınıza göre değişir
# 5. Slave konfigürasyonunu temizleyin
RESET SLAVE ALL;
MariaDB ile Uyumluluk Notları
Eğer MySQL yerine MariaDB kullanıyorsanız syntax bazı farklılıklar gösterir:
-- MariaDB'de SHOW SLAVE STATUS yerine
SHOW REPLICA STATUSG
-- MariaDB'de CHANGE MASTER TO yerine (10.5.1+)
CHANGE REPLICATION SOURCE TO
SOURCE_HOST = '192.168.1.100',
SOURCE_USER = 'replicator',
SOURCE_PASSWORD = 'GucluBirSifre123!',
SOURCE_LOG_FILE = 'mysql-bin.000003',
SOURCE_LOG_POS = 154;
-- MariaDB GTID syntax'ı
CHANGE MASTER TO MASTER_USE_GTID = slave_pos;
MariaDB’nin kendi GTID implementasyonu MySQL’den farklıdır, bu yüzden MariaDB master ile MySQL slave veya tersi kombinasyonlarda dikkatli olun.
Performans Optimizasyon İpuçları
Replikasyon gecikmesini minimize etmek için şu ayarları değerlendirin:
- binlog_format = ROW: Statement bazlı replikasyona göre daha güvenilir ama biraz daha fazla disk kullanır
- slave_parallel_workers: 0’dan büyük bir değer atayarak paralel replikasyon aktif edin, sunucu CPU sayısına göre ayarlayın
- innodb_flush_log_at_trx_commit = 2: Performansı artırır ama güç kesintisinde son saniyedeki veri kaybedilebilir, slave’lerde kabul edilebilir
- sync_binlog = 0: Slave’lerde binary log’u her commit’te diske yazmaz, performansı artırır
- relay_log_recovery = ON: Slave beklenmedik şekilde kapanırsa relay log tutarsızlıklarını otomatik düzeltir
Sonuç
MySQL Master-Slave replikasyonu, production veritabanı altyapısının temel taşlarından biridir. Doğru yapılandırıldığında hem veri güvenliği hem de performans açısından büyük kazanımlar sağlar. Bu yazıda ele aldığımız konuları özetlemek gerekirse:
Temel kurulum adımları artık elinizde. Master ve slave sunucu yapılandırması, replikasyon kullanıcısı oluşturma ve bağlantıyı sağlama konusunda net bir yol haritanız var. GTID kullanımını production ortamlarında tercih etmenizi özellikle öneririm, çünkü failover senaryolarında hayat kurtarıyor.
İzleme scriptini mutlaka kurun ve Nagios, Zabbix veya Prometheus gibi bir monitoring sistemine entegre edin. Replikasyonun sessiz sedasız bozulduğunu haftalarca fark etmeden çalışmaya devam edip ardından veri kaybıyla yüzleşmek oldukça acı verici bir deneyim. Bunu yaşayanlar bilir.
Son olarak, bu yapıyı test ortamında defalarca kurup failover senaryolarını prova etmeden production’a taşımayın. Kriz anında sakin kalabilmek için önceden pratik yapmak şart.