Tek bir veritabanı sunucusu, projeniz büyüdükçe iki ayrı baskı altında ezilmeye başlar: ya donanım arızalanır ve elinizde güncel bir kopya olmadığı için saatlerce ayakta kalamazsınız, ya da okuma sorguları o kadar artar ki tek sunucu istekleri yetiştiremez olur. Replikasyon her iki sorunu da aynı mekanizmayla çözer. Bir sunucudaki her değişikliği, gerçek zamanlıya yakın bir hızla bir veya daha fazla başka sunucuya kopyalar. Böylece hem sıcak bir yedeğiniz olur, hem de okuma trafiğini birden fazla makineye dağıtabilirsiniz.
Bu rehberde MySQL ve MariaDB üzerinde klasik master-slave (kaynak-kopya) replikasyonunu sıfırdan kuracağız. Master sunucuda binary log ve server_id yapılandırmasından, replikasyon kullanıcısı ve doğru yetkilerden, slave sunucuda başlangıç konumunu belirleyip senkronizasyonu başlatmaya ve durumu izlemeye kadar tüm adımları gerçek komutlarla ele alacağız. Sonda da üretimde en çok karşılaşacağınız hataları ve kopan bir replikasyonu nasıl toparlayacağınızı anlatacağız. Terminolojiyi tazelemek isterseniz MySQL veritabanı yönetimi yazımıza da göz atabilirsiniz.
Replikasyon Nedir ve Ne İşe Yarar#
Replikasyon, bir MySQL/MariaDB sunucusunda gerçekleşen tüm yazma işlemlerinin (INSERT, UPDATE, DELETE, DDL) binary log adı verilen bir günlük dosyasına kaydedilmesi ve bu günlüğün başka sunucular tarafından okunup birebir tekrar oynatılması esasına dayanır. Değişikliği üreten sunucuya master (yeni terminolojide source), kopyayı tutan sunucuya slave (yeni terminolojide replica) denir. Master yazma yapar, slave onu takip eder.
İki temel senaryoda hayat kurtarır. Birincisi yedeklilik ve iş sürekliliği: master çökerse elinizde saniyeler geriden gelen çalışır bir kopya vardır; uygulamayı ona yönlendirerek dakikalar içinde ayağa kalkarsınız. İkincisi okuma ölçekleme: e-ticaret, haber, forum gibi okuma ağırlıklı projelerde SELECT sorgularını bir veya birkaç slave'e dağıtır, master'ı yalnızca yazma için ayırırsınız. Ayrıca yedek almayı slave üzerinden yaptığınızda mysqldump sırasında master'a hiç yük binmez; raporlama gibi ağır sorguları da canlı sistemi yavaşlatmadan kopya üzerinde çalıştırabilirsiniz.
Şunu baştan netleştirelim: replikasyon bir yedekleme değildir. Master'da yanlışlıkla DROP TABLE çalıştırırsanız, o komut da saniyeler içinde slave'e gider ve tabloyu orada da siler. Bu yüzden replikasyonu her zaman düzenli, tarih damgalı yedeklerle birlikte kullanın; dosya tabanlı yedekler için rsync ile yedekleme yaklaşımı iyi bir tamamlayıcıdır.
Replikasyon Topolojileri ve Terimler#
Kuruluma geçmeden önce hangi mimariyi kurduğunuzu bilmeniz gerekir. En yaygın ve en kolay yönetilen topoloji tek master, bir veya birden çok slave'dir. Aşağıdaki tablo temel seçenekleri özetliyor.
| Topoloji | Yazma | Okuma | Kullanım alanı |
|---|---|---|---|
| Master → Slave | Yalnız master | Master + slave | Yedeklilik, basit okuma dağıtımı |
| Master → Çoklu Slave | Yalnız master | Birçok slave | Yüksek okuma trafiği, raporlama |
| Master ↔ Master | Her iki taraf | Her iki taraf | Aktif-aktif (dikkatli kurulmalı) |
| Zincir (A→B→C) | Yalnız A | B ve C | Coğrafi dağıtım, kademeli kopya |
Yeni başlıyorsanız Master → Slave ile başlayın; ihtiyaç oldukça slave ekleyebilirsiniz. Master ↔ Master (çift yönlü) yapılar çekici görünse de AUTO_INCREMENT çakışmaları ve çözümü zor tutarsızlıklar üretebildiği için bu rehberde tek yönlü kuruluma odaklanıyoruz.
Bir de senkronizasyon konumunu belirleme yönteminde iki yol vardır. Klasik yöntem binlog dosya adı + pozisyon ikilisini kullanır (mysql-bin.000003 ve 1547 gibi). Modern yöntem ise GTID (Global Transaction Identifier) kullanır; her işleme benzersiz bir kimlik atanır ve failover çok daha kolaylaşır. Bu yazıda her ikisine de değineceğiz ama ana kurulumu, kavramsal olarak daha şeffaf olduğu için klasik pozisyon yöntemiyle yapacağız.
Master Sunucuyu Yapılandırma#
İlk iş master'da binary log'u açmak ve sunucuya benzersiz bir kimlik vermektir. Replikasyondaki her sunucunun ağ genelinde eşsiz bir server_id değeri olmalıdır; aynı id'yi iki makinede kullanırsanız replikasyon sessizce bozulur. Yapılandırma dosyasını açın (Debian/Ubuntu'da genelde /etc/mysql/mysql.conf.d/mysqld.cnf, MariaDB'de /etc/mysql/mariadb.conf.d/50-server.cnf) ve [mysqld] bölümüne şunları ekleyin.
[mysqld]
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
binlog_expire_logs_seconds = 604800
bind_address = 0.0.0.0
binlog_format = ROW, satır bazlı günlükleme yapar ve tetikleyici, saat fonksiyonu gibi belirsiz durumlarda master ile slave arasında tutarlılığı garanti eden en güvenli seçenektir. binlog_expire_logs_seconds eski günlükleri (burada 7 gün) otomatik temizleyerek diskin dolmasını engeller; MariaDB'de bunun karşılığı expire_logs_days = 7 şeklindedir. bind_address değerini 0.0.0.0 yapmak sunucunun ağ üzerinden erişilebilir olmasını sağlar; güvenlik için bunu yalnızca özel ağ arayüzüne (örneğin 10.0.0.1) bağlamanız ve slave IP'sini firewall'da açmanız daha doğrudur.
Değişikliklerin geçerli olması için servisi yeniden başlatın ve binary log'un gerçekten açıldığını doğrulayın.
sudo systemctl restart mysql
mysql -u root -p -e "SHOW MASTER STATUS\G"
SHOW MASTER STATUS size boş olmayan bir File ve Position döndürüyorsa master hazır demektir. MySQL 8.0.22 ve sonrasında bu komut SHOW BINARY LOG STATUS olarak da çalışır; ikisi de aynı bilgiyi verir. Bu değerleri birazdan slave'i konumlandırırken kullanacağız, ama önce doğru anı yakalamak için verileri dondurmamız gerekecek.
Replikasyon Kullanıcısı Oluşturma#
Slave, master'a normal bir istemci gibi bağlanıp binary log'u okur. Bu bağlantı için özel bir kullanıcı açıyoruz. Bu kullanıcıya yalnızca REPLICATION SLAVE yetkisi verin; tablolarınızı okuma veya yazma yetkisine ihtiyacı yoktur, dolayısıyla en dar yetkiyle ilerlemek güvenlik açısından doğru olandır. Master üzerinde çalıştırın.
CREATE USER 'repl'@'10.0.0.2' IDENTIFIED BY 'CokGucluBirParola!42';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.0.2';
FLUSH PRIVILEGES;
Burada 'repl'@'10.0.0.2' ifadesindeki IP, slave sunucunuzun adresidir. Kullanıcıyı 'repl'@'%' şeklinde her yerden erişilebilir yapmak yerine tek bir IP'ye kısıtlamak, replikasyon kimlik bilgilerinin başka bir makineden kötüye kullanılma riskini büyük ölçüde azaltır. Birden çok slave kuracaksanız her biri için ayrı bir satır ekleyebilir veya alt ağı (10.0.0.%) verebilirsiniz.
MySQL 8'de varsayılan kimlik doğrulama eklentisi caching_sha2_password'tur ve şifrelenmemiş bağlantılarda replikasyon kullanıcısıyla sorun çıkarabilir. TLS kullanmıyorsanız kullanıcıyı IDENTIFIED WITH mysql_native_password BY '...' ile oluşturmak en pratik çözümdür; üretimde ise doğrusu master-slave trafiğini SSL ile şifrelemektir. Sertifika yönetimi konusunda SSL sertifikaları tarafındaki içeriğimiz mantığı kavramanıza yardımcı olur.
Verileri Senkronize Etme ve Başlangıç Konumu#
Slave, master'ın mevcut durumundan başlayarak takip etmelidir. Yani master'daki tüm veriyi bir kez slave'e taşımanız ve tam o anın binlog pozisyonunu not etmeniz gerekir. En güvenli yol mysqldump'ın --master-data seçeneğidir; bu seçenek döküm dosyasının içine CHANGE MASTER konumunu otomatik yazar, böylece pozisyonu elle kopyalarken hata yapma ihtimali ortadan kalkar.
Master üzerinde tam bir döküm alın.
mysqldump -u root -p \
--all-databases \
--master-data=2 \
--single-transaction \
--routines --triggers --events \
| gzip > /root/master-full.sql.gz
--single-transaction, InnoDB tablolarında tabloları kilitlemeden tutarlı bir anlık görüntü alır; bu sayede döküm sürerken uygulamanız yazmaya devam edebilir. --master-data=2 ise CHANGE MASTER TO MASTER_LOG_FILE=... MASTER_LOG_POS=... satırını dosyanın başına yorum olarak ekler. Dosyanın içindeki o satırı görmek isterseniz şöyle bakabilirsiniz.
zcat /root/master-full.sql.gz | head -30 | grep "CHANGE MASTER"
Şimdi dökümü slave'e taşıyıp yükleyin. Büyük veritabanlarında bu dosyayı ağ üzerinden aktarmak için rsync ile yedekleme yazısındaki transfer yöntemleri işinizi kolaylaştırır.
scp /root/master-full.sql.gz [email protected]:/root/
# Slave üzerinde:
zcat /root/master-full.sql.gz | mysql -u root -p
Bu adım bitince slave, master'ın döküm anındaki birebir kopyasına sahip olur ve hangi binlog pozisyonundan devam etmesi gerektiğini de dosyanın içinden öğrenmiş olur. MyISAM tablolarınız varsa --single-transaction onları tutarlı almaz; o durumda döküm süresince master'da FLUSH TABLES WITH READ LOCK ile kısa bir okuma kilidi almanız gerekir.
Slave Sunucuda CHANGE MASTER ve Başlatma#
Slave'in de kendi server_id değeri olmalı. Yapılandırma dosyasına şunları ekleyip servisi yeniden başlatın. read_only, uygulamanın yanlışlıkla slave'e yazmasını engelleyerek tutarlılığı korur.
[mysqld]
server_id = 2
relay_log = /var/log/mysql/mysql-relay-bin.log
read_only = 1
log_slave_updates = 1
Şimdi slave'e master'ın adresini, replikasyon kullanıcısını ve başlangıç pozisyonunu bildiriyoruz. Eğer --master-data=1 kullandıysanız CHANGE MASTER satırı dökümle birlikte otomatik çalışmış olur; =2 kullandığımız için pozisyonu elle giriyoruz. Döküm başındaki yorumdan aldığınız dosya adı ve pozisyonu buraya yazın.
CHANGE MASTER TO
MASTER_HOST = '10.0.0.1',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'CokGucluBirParola!42',
MASTER_LOG_FILE = 'mysql-bin.000003',
MASTER_LOG_POS = 1547;
START SLAVE;
MySQL 8.0.23 ve sonrasında bu komutların adları değişti; CHANGE MASTER TO yerine CHANGE REPLICATION SOURCE TO (SOURCE_HOST, SOURCE_USER, SOURCE_LOG_FILE gibi anahtarlarla) ve START SLAVE yerine START REPLICA kullanılır. Eski komutlar hâlâ takma ad olarak çalışsa da yeni kurulumlarda güncel adları tercih edin. MariaDB tarafında ise komut adları klasik CHANGE MASTER / START SLAVE biçiminde kalmaya devam eder.
GTID kullanmak isterseniz pozisyon yerine tek satır yeter: master ve slave'de gtid_mode = ON (MariaDB'de gtid_strict_mode) açıkken CHANGE MASTER TO MASTER_HOST=..., MASTER_USER=..., MASTER_AUTO_POSITION=1; demeniz yeterlidir; sunucular ortak GTID geçmişine bakıp doğru noktadan senkron olur.
Replikasyon Durumunu İzleme#
Replikasyonu başlattıktan sonra sağlığını mutlaka doğrulayın. Slave üzerinde tek komut her şeyi anlatır.
SHOW SLAVE STATUS\G
Çıktıda üç satıra bakın. Slave_IO_Running ve Slave_SQL_Running değerlerinin ikisi de Yes olmalı; ilki master'dan günlüğü çekiyor, ikincisi çekilen günlüğü uyguluyor demektir. Üçüncüsü Seconds_Behind_Master: slave'in master'dan kaç saniye geride olduğunu gösterir. Sağlıklı bir sistemde bu değer 0 veya çok küçük olmalıdır. Değer sürekli büyüyorsa slave yazmaları yetiştiremiyordur; daha güçlü disk veya donanım gerekebilir.
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
Last_IO_Errno: 0
Last_SQL_Errno: 0
Gerçekten çalıştığını kanıtlamak için master'da küçük bir test yapın: bir test veritabanı oluşturup içine kayıt atın, ardından slave'de aynı kaydın belirdiğini görün.
-- Master'da:
CREATE DATABASE replikasyon_testi;
CREATE TABLE replikasyon_testi.kontrol (id INT, not_ VARCHAR(50));
INSERT INTO replikasyon_testi.kontrol VALUES (1, 'merhaba slave');
-- Slave'de birkaç saniye sonra:
SELECT * FROM replikasyon_testi.kontrol;
MySQL 8.0.22 sonrası SHOW SLAVE STATUS yerine SHOW REPLICA STATUS kullanılır ve alanlar Replica_IO_Running, Replica_SQL_Running gibi adlandırılır. İzlemeyi otomatikleştirmek için Seconds_Behind_Master ve Slave_SQL_Running değerlerini bir kontrol betiğiyle periyodik sorgulayıp eşik aşıldığında uyarı üretmek üretim ortamları için şiddetle önerilir.
Okuma Yükünü Dağıtma#
Replikasyon çalışır hâle geldikten sonra asıl kazanımı uygulamanıza yansıtmalısınız: yazmaları master'a, okumaları slave'e yönlendirmek. Bunu üç şekilde yapabilirsiniz. En basiti, uygulama kodunda iki ayrı bağlantı havuzu tutmaktır; INSERT/UPDATE/DELETE master bağlantısına, SELECT slave bağlantısına gider. Birçok framework (Laravel, Django, Rails) bu "read/write splitting" ayrımını yapılandırmayla destekler.
İkinci yol, uygulama koduna hiç dokunmadan araya bir proxy koymaktır. ProxySQL veya MariaDB MaxScale, gelen sorguyu ayrıştırır ve okuma/yazmayı otomatik olarak doğru sunucuya yönlendirir; slave çökerse trafiği yeniden dağıtır. Aşağıda ProxySQL'de basit bir sunucu tanımı görüyorsunuz.
-- ProxySQL yönetim arayüzünde
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (10, '10.0.0.1', 3306); -- yazma grubu
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (20, '10.0.0.2', 3306); -- okuma grubu
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
Dağıtırken replikasyon gecikmesini unutmayın. Bir kullanıcı yorum yazıp hemen sayfayı yenilediğinde, o okuma henüz gecikmiş bir slave'e giderse yorumu göremeyebilir. Bu tür "kendi yazdığını hemen okuma" senaryolarında ilgili SELECT'i bilinçli olarak master'a yönlendirin. Kendi altyapınızı yönetiyorsanız bu ayrımı sunucu yönetimi hizmetimizle birlikte kurgulamak yükünüzü hafifletir; sıfırdan bir kopya sunucuya ihtiyacınız varsa VDS sunucular hızlı bir başlangıç sağlar.
Sık Karşılaşılan Hatalar ve Kopan Replikasyonu Onarma#
Üretimde en sık gördüğünüz iki hata Slave_SQL_Running: No ile birlikte gelen 1062 (Duplicate entry) ve 1032 (Can't find record) hatalarıdır. 1062, slave'de zaten var olan bir birincil anahtarı tekrar eklemeye çalışıldığında; 1032 ise slave'de olmayan bir satırı güncelleme/silme denendiğinde çıkar. İkisinin de kök nedeni genellikle aynıdır: slave bir noktada master ile tutarsız hâle gelmiştir (yanlışlıkla slave'e elle yazılmış, sunucu düzgün kapanmamış vb.).
Hatayı görmek için önce SHOW SLAVE STATUS\G çıktısındaki Last_SQL_Error alanını okuyun. Etkisi önemsiz, tek seferlik bir çakışmaysa ve nedeninden eminseniz, sorunlu tek işlemi atlayıp devam edebilirsiniz.
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;
SHOW SLAVE STATUS\G
GTID kullanıyorsanız sql_slave_skip_counter çalışmaz; bunun yerine sorunlu işlemin GTID'sini boş bir işlemle geçersiz kılmanız gerekir. Ancak bu tür "atla ve devam et" müdahaleleri veriyi kalıcı olarak sapmaya bırakabilir. Slave ile master arasındaki fark birden fazla tabloya yayılmışsa doğru olan tek şey slave'i sıfırdan yeniden kurmaktır: master'dan taze bir mysqldump --master-data alın, slave'e yükleyin, CHANGE MASTER ile yeni pozisyondan başlatın. Tutarlılığın önemli olduğu sistemlerde birkaç işlemi atlamaktansa yeniden senkron etmek her zaman daha güvenlidir.
Slave_IO_Running: Connecting gibi ağ tabanlı hatalarda ise soruna master tarafından bakın: firewall'da 3306 portunun slave IP'sine açık olduğunu, replikasyon kullanıcısının doğru host ile tanımlandığını ve bind_address değerinin bağlantıya izin verdiğini doğrulayın. Aşağıdaki bir satır çoğu bağlantı sorununu hızla yerinde tespit ettirir.
mysql -h 10.0.0.1 -u repl -p -e "SELECT 1;"
Bu komut slave üzerinden çalışıyor ve 1 dönüyorsa ağ ve kimlik doğrulama katmanı sağlıklı demektir; sorun yapılandırmadadır. Bağlantı hatası alıyorsanız düğüm master'a hiç ulaşamıyordur.
Sıkça Sorulan Sorular#
Replikasyon yedekleme yerine geçer mi?#
Hayır, replikasyon bir yedekleme değildir ve onun yerini tutmaz. Master'da yapılan yanlış bir DELETE veya DROP komutu saniyeler içinde slave'e de kopyalanır ve orada da aynı hasarı yaratır. Replikasyon size donanım arızasına karşı sıcak bir kopya sağlar, ancak insan hatasına veya veri bozulmasına karşı korumaz. Bu yüzden replikasyonu her zaman düzenli, tarih damgalı ve mümkünse dış konumda saklanan yedeklerle birlikte kullanmalısınız.
MySQL ve MariaDB arasında replikasyon kurulabilir mi?#
Sınırlı ve önerilmeyen bir senaryo olsa da genellikle MariaDB, bir MySQL master'ından replikasyon alabilir; çünkü MariaDB uzun süre MySQL binary log formatıyla uyumlu kaldı. Ancak ters yön (MySQL slave, MariaDB master) ve özellikle MySQL 8 ile MariaDB 10.x arası GTID uyumsuzlukları çok sorunludur. Üretimde en sağlıklı yol, master ve slave'in aynı motorun aynı ana sürümünü çalıştırmasıdır; sürüm karışıklığı zamanla çözülmesi zor tutarsızlıklar doğurur.
Slave sunucu master'dan kaç saniye geride olabilir?#
Sağlıklı bir kurulumda Seconds_Behind_Master değeri sıfır veya birkaç saniye olmalıdır. Bu değerin sürekli büyümesi, slave'in master'ın yazma hızına yetişemediğini gösterir. En sık nedenleri slave'in daha zayıf diskine sahip olması, tek iş parçacıklı SQL uygulama süreci veya master'da tek seferde çalışan çok büyük işlemlerdir. Çözüm olarak slave'de paralel replikasyonu açabilir, disk performansını artırabilir veya büyük toplu işlemleri master'da küçük parçalara bölebilirsiniz.
Replikasyon kullanıcısına hangi yetkileri vermeliyim?#
Replikasyon kullanıcısının yalnızca REPLICATION SLAVE yetkisine ihtiyacı vardır ve başka hiçbir yetki verilmemelidir. Bu kullanıcı tablolarınızı okumaz, yazmaz veya değiştirmez; sadece binary log akışını çeker. En dar yetki ilkesine sadık kalmak, kimlik bilgileri sızsa bile verinize erişim riskini en aza indirir. Ayrıca kullanıcıyı 'repl'@'%' gibi her yerden değil, yalnızca slave sunucunuzun IP adresine kısıtlayarak tanımlamak güvenliği belirgin biçimde artırır.
GTID mi yoksa klasik binlog pozisyonu mu kullanmalıyım?#
Yeni bir kurulum yapıyorsanız ve sürümleriniz destekliyorsa GTID kullanmanızı öneririz. GTID, her işleme benzersiz bir kimlik atadığı için özellikle failover (master değiştirme) ve slave'i başka bir master'a bağlama senaryolarında pozisyonu elle hesaplama derdini tamamen ortadan kaldırır. Klasik binlog dosya adı ve pozisyon yöntemi ise kavramsal olarak daha şeffaftır ve öğrenme aşamasında ne olup bittiğini görmenizi kolaylaştırır; bu yüzden bu rehberde ana kurulumu onunla anlattık.
Kapanış#
MySQL ve MariaDB replikasyonu, doğru kurulduğunda hem uykularınızı rahatlatan bir yedeklilik hem de büyümeye hazır bir okuma ölçekleme katmanı sağlar. Özetle akış nettir: master'da server_id ve binary log'u açın, dar yetkili bir replikasyon kullanıcısı oluşturun, tutarlı bir mysqldump ile veriyi taşıyıp doğru başlangıç pozisyonunu yakalayın, slave'de CHANGE MASTER ile bağlanıp START SLAVE deyin ve SHOW SLAVE STATUS ile düzenli izleyin. Kopmalar olduğunda ise küçük çakışmaları bilinçli atlayabilir, ama fark büyüdüğünde tereddüt etmeden slave'i yeniden senkronize edebilirsiniz.
Bu mimariyi kurmak için sağlam, tam yetkili ve kaynakları garantili bir altyapıya ihtiyacınız olur. Kopya veritabanınızı barındırmak için VDS sunucular veya sanal sunucu çözümlerimize, yönetim yükünü bize bırakmak isterseniz sunucu yönetimi hizmetimize göz atabilirsiniz. Master-slave trafiğini şifrelemek için SSL, düzenli yedekleme kurgusu için yedekleme hizmetlerimiz de bu resmi tamamlar. Veritabanı temellerini tazelemek isterseniz MySQL veritabanı yönetimi yazımız iyi bir sonraki adımdır. Clou.TR ekibi olarak kurulumun her aşamasında yanınızdayız.