MySQL Galera Cluster ile Yüksek Erişilebilirlik

Veritabanı katmanında tek nokta arızası (single point of failure) yaşamak, gecenin üçünde telefon almak demektir. MySQL Galera Cluster tam da bu kabusu önlemek için var. Birden fazla node üzerinde senkron replikasyon yaparak hem yüksek erişilebilirlik hem de otomatik failover sağlar. Bu yazıda sıfırdan kurulumdan, izleme ve sorun gidermeye kadar her şeyi ele alacağız.

Galera Cluster Nedir ve Nasıl Çalışır?

Galera, MySQL/MariaDB üzerine inşa edilmiş bir senkron multi-master replikasyon kütüphanesidir. Klasik MySQL master-slave yapısından temel farkı şudur: Galera’da her node hem okuma hem yazma kabul eder ve bir transaction commit edilebilmesi için cluster’daki node’ların çoğunluğunun onayı gerekir. Bu mekanizmaya writeset replication denir.

Temel çalışma prensibi şöyle özetlenebilir:

  • Senkron replikasyon: Bir node’a yazılan veri, commit anında tüm node’lara yayılır, asenkron gecikmesi yoktur.
  • Certification based replication: Her transaction bir writeset olarak paketlenir ve tüm node’larda çakışma kontrolünden geçer.
  • Automatic node provisioning: Yeni bir node cluster’a katıldığında SST (State Snapshot Transfer) veya IST (Incremental State Transfer) ile otomatik senkronize olur.
  • Quorum mekanizması: Node sayısının yarısından fazlası ayakta olduğu sürece cluster çalışmaya devam eder. Bu yüzden minimum 3 node önerilir.

Galera’nın bir dezavantajı da var: Her yazma işlemi tüm node’lara yayıldığı için ağ gecikmesi kritik hale gelir. Aynı datacenter içinde harika çalışır ama coğrafi olarak dağık node’larda dikkatli olunmalıdır.

Lab Ortamı ve Ön Hazırlık

Bu yazıda 3 node’lu bir Galera Cluster kuracağız. Sunucu bilgileri şu şekilde:

  • galera-node1: 192.168.10.11
  • galera-node2: 192.168.10.12
  • galera-node3: 192.168.10.13

İşletim sistemi olarak Ubuntu 22.04 kullanıyorum, MariaDB 10.11 üzerinde Galera 4 çalışacak. Tüm komutları aksi belirtilmedikçe her üç node’da da çalıştırmanız gerekiyor.

Sistem Hazırlığı

Önce hostname ve hosts ayarlarını yapalım. Her node’da kendi hostname’ini ve diğerlerinin IP-hostname eşleşmelerini /etc/hosts dosyasına ekleyelim:

# Her node'da ilgili hostname'i set et
# galera-node1 üzerinde:
hostnamectl set-hostname galera-node1

# /etc/hosts dosyasına tüm node'larda ekle:
cat >> /etc/hosts << 'EOF'
192.168.10.11 galera-node1
192.168.10.12 galera-node2
192.168.10.13 galera-node3
EOF

Firewall kurallarını da ayarlamamız gerekiyor. Galera şu portları kullanır:

  • 3306: MySQL istemci bağlantıları
  • 4444: SST (State Snapshot Transfer)
  • 4567: Galera cluster replikasyon trafiği (TCP ve UDP)
  • 4568: IST (Incremental State Transfer)
# UFW ile port açma (tüm node'larda)
ufw allow from 192.168.10.0/24 to any port 3306
ufw allow from 192.168.10.0/24 to any port 4444
ufw allow from 192.168.10.0/24 to any port 4567
ufw allow from 192.168.10.0/24 to any port 4568
ufw reload

MariaDB ve Galera Kurulumu

# MariaDB repository ekle
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | 
  sudo bash -s -- --mariadb-server-version="mariadb-10.11"

# Galera dahil MariaDB kur
apt update
apt install -y mariadb-server mariadb-client galera-4 rsync

# Servisi şimdilik durdur
systemctl stop mariadb

Kurulum tamamlandıktan sonra temel güvenlik ayarlarını yapalım:

# mysql_secure_installation çalıştır
mysql_secure_installation
# Root şifresi belirle, anonymous user kaldır, test db kaldır

Galera Konfigürasyonu

Bu adım en kritik kısım. Her node’da /etc/mysql/conf.d/galera.cnf dosyasını oluşturacağız. İçerik node’dan node’a küçük farklılıklar gösteriyor.

galera-node1 için /etc/mysql/conf.d/galera.cnf:

cat > /etc/mysql/conf.d/galera.cnf << 'EOF'
[mysqld]
# Temel Galera ayarları
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Cluster ayarları
wsrep_cluster_name="galera_production"
wsrep_cluster_address="gcomm://192.168.10.11,192.168.10.12,192.168.10.13"

# Node kimlik bilgileri
wsrep_node_address="192.168.10.11"
wsrep_node_name="galera-node1"

# SST yöntemi
wsrep_sst_method=rsync

# Performance ayarları
wsrep_slave_threads=4
innodb_flush_log_at_trx_commit=0
innodb_buffer_pool_size=1G
EOF

Node2 ve Node3 için sadece wsrep_node_address ve wsrep_node_name satırlarını değiştirmeniz yeterli:

# galera-node2 için bu iki satırı değiştir:
wsrep_node_address="192.168.10.12"
wsrep_node_name="galera-node2"

# galera-node3 için:
wsrep_node_address="192.168.10.13"
wsrep_node_name="galera-node3"

Bazı önemli parametreleri açıklayalım:

  • wsrep_on=ON: Galera replikasyonunu aktif eder.
  • innodb_autoinc_lock_mode=2: Multi-master ortamında auto increment çakışmalarını önler, interleaved modu kullanır.
  • binlog_format=ROW: Galera sadece ROW formatını destekler, statement-based çalışmaz.
  • wsrep_sst_method=rsync: Yeni node eklenirken tam snapshot için rsync kullanılır. Mariabackup da iyi bir alternatiftir, özellikle büyük veritabanlarında downtime’ı azaltır.
  • wsrep_slave_threads=4: Replikasyon için kullanılacak thread sayısı. CPU core sayısının 1-1.5 katı genellikle iyi bir başlangıç noktasıdır.

Cluster’ı Başlatma

İlk bootstrap işlemi önemli. Cluster’ı sıfırdan başlatmak için ilk node’u özel bir komutla açmamız gerekiyor:

# SADECE galera-node1 üzerinde, ilk kez başlatmak için:
galera_new_cluster

# Cluster durumunu kontrol et
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
# Sonuç: 1 (henüz sadece bu node var)

Şimdi diğer node’ları normal şekilde başlatabiliriz:

# galera-node2 ve galera-node3 üzerinde:
systemctl start mariadb

# Birkaç saniye bekle, sonra node1'de kontrol et:
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep%';"

wsrep_cluster_size değerinin 3 olduğunu görmeniz gerekiyor. wsrep_local_state_comment ise Synced olmalıdır.

Cluster Sağlık Kontrolü

Galera’yı izlemek için kullanabileceğiniz temel sorguları bir script haline getirelim:

#!/bin/bash
# galera_health_check.sh

MYSQL_USER="root"
MYSQL_PASS="sifreniz"
LOG_FILE="/var/log/galera_health.log"

check_galera() {
  local host=$1
  echo "=== $host Galera Durumu ===" | tee -a $LOG_FILE
  
  mysql -u $MYSQL_USER -p$MYSQL_PASS -h $host -e "
    SELECT VARIABLE_NAME, VARIABLE_VALUE 
    FROM information_schema.GLOBAL_STATUS 
    WHERE VARIABLE_NAME IN (
      'WSREP_CLUSTER_SIZE',
      'WSREP_CLUSTER_STATUS',
      'WSREP_LOCAL_STATE_COMMENT',
      'WSREP_READY',
      'WSREP_FLOW_CONTROL_PAUSED',
      'WSREP_CERT_DEPS_DISTANCE'
    );
  " 2>/dev/null | tee -a $LOG_FILE
}

for node in 192.168.10.11 192.168.10.12 192.168.10.13; do
  check_galera $node
done

# Kritik değerleri kontrol et
CLUSTER_SIZE=$(mysql -u $MYSQL_USER -p$MYSQL_PASS -e 
  "SHOW STATUS LIKE 'wsrep_cluster_size';" 2>/dev/null | awk '/wsrep_cluster_size/{print $2}')

if [ "$CLUSTER_SIZE" -lt 3 ]; then
  echo "UYARI: Cluster size $CLUSTER_SIZE! Bir veya daha fazla node kayıp!" | 
    tee -a $LOG_FILE
  # Buraya alert mekanizmanı ekle (mail, slack webhook vs.)
fi

Bu scripti cron ile her 5 dakikada bir çalıştırabilirsiniz:

chmod +x /usr/local/bin/galera_health_check.sh
echo "*/5 * * * * root /usr/local/bin/galera_health_check.sh" > /etc/cron.d/galera_health

HAProxy ile Load Balancing

Galera her node’un yazma kabul etmesiyle birlikte gelir ama uygulama katmanında hangi node’a bağlanacağınızı yönetmek için bir load balancer gereklidir. HAProxy bu iş için mükemmeldir. Ayrı bir sunucuya (veya keepalived ile iki HAProxy’yi aktif-pasif yapılandırarak) kurabilirsiniz:

apt install -y haproxy

cat > /etc/haproxy/haproxy.cfg << 'EOF'
global
    log /dev/log local0
    maxconn 50000
    user haproxy
    group haproxy
    daemon

defaults
    log global
    mode tcp
    option tcplog
    option dontlognull
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

# İstatistik arayüzü
listen stats
    bind *:8080
    stats enable
    stats uri /haproxy_stats
    stats refresh 10s
    stats auth admin:guclu_sifre

# MySQL yük dengeleme
listen mysql_cluster
    bind *:3306
    mode tcp
    balance leastconn
    option mysql-check user haproxy_check
    
    server galera-node1 192.168.10.11:3306 check weight 1
    server galera-node2 192.168.10.12:3306 check weight 1
    server galera-node3 192.168.10.13:3306 check weight 1
EOF

systemctl restart haproxy

HAProxy’nin MySQL health check yapabilmesi için cluster’da özel bir kullanıcı oluşturun:

# Herhangi bir Galera node'unda çalıştır, tüm node'lara yayılır:
mysql -u root -p -e "
  CREATE USER 'haproxy_check'@'%' IDENTIFIED BY '';
  FLUSH PRIVILEGES;
"

Gerçek Dünya Senaryosu: Node Kaybı ve Recovery

Üretim ortamında en sık karşılaştığım senaryo şu: Bir node beklenmedik şekilde kapanıyor, diskten doluyor veya network bölünmesi (split-brain) yaşanıyor.

Normal Node Kaybı

Bir node kapandığında Galera otomatik olarak devam eder (quorum korunduğu sürece). Node tekrar ayağa kalktığında IST ile otomatik senkronize olur:

# node2 çöktükten sonra tekrar başlatma
systemctl start mariadb

# Senkronizasyon durumunu izle
watch -n 1 'mysql -u root -p"sifre" -e "SHOW STATUS LIKE "wsrep_local_state_comment";" 2>/dev/null'
# Joining -> Joined -> Synced geçişini göreceksin

Split-Brain Durumu

2 node’un birbirinden haberdar olamadığı ama her ikisinin de çalışmaya devam ettiği durum tehlikelidir. Galera quorum mekanizması sayesinde azınlıktaki node write işlemlerini reddeder:

# Hangi node'un "Primary Component" olduğunu kontrol et
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_status';"
# Primary: Normal çalışıyor
# Non-Primary: Bu node yazma kabul etmiyor, quorum kaybetti

Eğer tüm cluster kapandıysa ve hangi node’un en güncel olduğunu bulmak istiyorsanız:

# Her node'da kontrol et
cat /var/lib/mysql/grastate.dat
# seqno değeri en yüksek olan node en güncel veriyi içeriyor
# safe_to_bootstrap: 1 olan node bootstrap için hazır

Tam Cluster Recovery

En kötü senaryo: Tüm node’lar kapandı ve cluster’ı sıfırdan kaldırmanız gerekiyor:

# En yüksek seqno'ya sahip node'da (grastate.dat'ta safe_to_bootstrap: 0 ise önce 1 yap)
# /var/lib/mysql/grastate.dat dosyasını düzenle:
sed -i 's/safe_to_bootstrap: 0/safe_to_bootstrap: 1/' /var/lib/mysql/grastate.dat

# Sadece bu node'da bootstrap:
galera_new_cluster

# Diğer node'ları sırayla başlat:
# node2 ve node3 üzerinde:
systemctl start mariadb

Uyarı: safe_to_bootstrap değerini manuel olarak değiştirmek veri kaybına yol açabilir. Bunu sadece hangi node’un en güncel olduğundan emin olduğunuzda yapın.

Performans Optimizasyonu

Galera’yı üretimde çalıştırırken birkaç kritik ayar performansı doğrudan etkiler:

# /etc/mysql/conf.d/galera.cnf dosyasına eklenecek performance ayarları

[mysqld]
# Flow control - replikasyon baskısını yönetir
wsrep_provider_options="gcache.size=512M; gcs.fc_limit=100; gcs.fc_factor=0.8"

# Paralel replikasyon - çok yazmalı ortamlarda kritik
wsrep_slave_threads=8

# InnoDB buffer pool - RAM'in %70-80'i
innodb_buffer_pool_size=8G
innodb_buffer_pool_instances=8

# Binary log kapatılabilir (sadece Galera replication kullanıyorsa)
# Ama point-in-time recovery için açık tutmak daha güvenli
# skip-log-bin

# Deadlock olasılığını azalt
innodb_deadlock_detect=ON
innodb_lock_wait_timeout=50

gcache.size parametresi özellikle önemlidir. Bu cache, node yeniden bağlandığında IST için kullanılır. Eğer bir node çok uzun süre offline kaldıysa ve gcache bu süredeki değişiklikleri tutamıyorsa, sistem SST’ye (tam snapshot) geçmek zorunda kalır ki bu çok daha yavaştır. Yazma yoğunluğuna göre 512MB ile 2GB arasında ayarlamak mantıklıdır.

Monitoring: Prometheus ve Grafana Entegrasyonu

Uzun vadede Galera’yı izlemek için mysqld_exporter kullanabilirsiniz:

# mysqld_exporter kur
wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz
tar xzf mysqld_exporter-0.15.1.linux-amd64.tar.gz
mv mysqld_exporter-0.15.1.linux-amd64/mysqld_exporter /usr/local/bin/

# Exporter için MySQL kullanıcısı oluştur
mysql -u root -p -e "
  CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'exporter_sifre';
  GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
  FLUSH PRIVILEGES;
"

# Credentials dosyası
cat > /etc/mysql/.my.cnf << 'EOF'
[client]
user=exporter
password=exporter_sifre
EOF
chmod 600 /etc/mysql/.my.cnf

# Systemd service
cat > /etc/systemd/system/mysqld_exporter.service << 'EOF'
[Unit]
Description=MySQL Exporter
After=network.target

[Service]
User=prometheus
ExecStart=/usr/local/bin/mysqld_exporter 
  --config.my-cnf=/etc/mysql/.my.cnf 
  --collect.global_status 
  --collect.info_schema.innodb_metrics 
  --web.listen-address=:9104
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now mysqld_exporter

Grafana’da Galera için kullanabileceğiniz hazır dashboard ID’leri şunlardır: 7362 (MySQL Overview) ve özellikle wsrep metriklerini gösteren custom dashboard’lar community tarafından paylaşılmaktadır.

İzlemeniz gereken kritik metrikler:

  • wsrep_cluster_size: Her zaman 3 olmalı (3 node’lu cluster için)
  • wsrep_flow_control_paused: 0’a yakın olmalı, yüksekse replikasyon baskı altında
  • wsrep_cert_deps_distance: Paralel uygulanabilecek transaction sayısı, wsrep_slave_threads ayarı için referans
  • wsrep_local_send_queue_avg: Gönderim kuyruğu, ağ sorunlarının göstergesi
  • wsrep_local_recv_queue_avg: Alım kuyruğu, node’un gelen trafiği kaldıramadığını gösterir

Backup Stratejisi

Galera çalışıyor diye backup almayı ihmal etmeyin. Multi-master yapı veri kaybına karşı koruma sağlar ama mantıksal hataları (yanlışlıkla silinen tablo gibi) engellemez.

#!/bin/bash
# galera_backup.sh - Mariabackup ile hot backup

BACKUP_DIR="/backup/galera/$(date +%Y%m%d_%H%M%S)"
MYSQL_USER="root"
MYSQL_PASS="sifreniz"
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR

echo "Backup başlıyor: $(date)"

# Mariabackup ile hot backup (servisi durdurmadan)
mariabackup --backup 
  --target-dir=$BACKUP_DIR 
  --user=$MYSQL_USER 
  --password=$MYSQL_PASS 
  --galera-info  # Bu parametre Galera seqno bilgisini de kaydeder

# Backup'ı hazırla (prepare aşaması)
mariabackup --prepare --target-dir=$BACKUP_DIR

# Eski backup'ları temizle
find /backup/galera -maxdepth 1 -type d -mtime +$RETENTION_DAYS -exec rm -rf {} ;

echo "Backup tamamlandı: $BACKUP_DIR"
echo "Boyut: $(du -sh $BACKUP_DIR | cut -f1)"

--galera-info parametresi backup dizinine xtrabackup_galera_info dosyası oluşturur. Bu dosya backup anındaki wsrep_local_state_uuid ve wsrep_last_committed değerlerini içerir; restore sonrası IST kullanmak istediğinizde bu bilgilere ihtiyacınız olabilir.

Sık Karşılaşılan Sorunlar

SST takılı kalıyor: Büyük veritabanlarında rsync yerine mariabackup kullanın. wsrep_sst_method=mariabackup daha güvenilirdir ve donor node’u kilitlemez.

Yüksek replikasyon gecikmesi: wsrep_flow_control_paused değerine bakın. Yüksekse en yavaş node tüm cluster’ı yavaşlatıyor demektir. O node’u inceleyin, donanım sorunu veya ağ problemi olabilir.

Auto increment çakışmaları: innodb_autoinc_lock_mode=2 ayarının yapıldığından emin olun. Ayrıca wsrep_auto_increment_control=ON varsayılan olarak aktiftir ve her node farklı aralıklarda ID üretir (node1: 1,4,7… node2: 2,5,8… node3: 3,6,9…).

Node cluster’a katılamıyor: wsrep_cluster_address içindeki IP’leri kontrol edin. Firewall kurallarını ve SELinux/AppArmor politikalarını gözden geçirin.

Sonuç

MySQL Galera Cluster, doğru kurulduğunda gerçekten güvenilir bir yüksek erişilebilirlik çözümü sunar. Senkron replikasyon sayesinde veri kaybı riski minimize edilir, herhangi bir node otomatik olarak failover alır ve uygulamanız kesintisiz çalışmaya devam eder.

Ancak şunu unutmayın: Galera sihirli bir değnek değil. Ağ kalitesi, node boyutlarının dengeli tutulması ve düzenli izleme olmadan cluster zamanla sorun çıkarır. Özellikle wsrep_flow_control_paused metriğini sürekli izleyin, bu tek başına cluster’ın sağlık durumu hakkında çok şey söyler.

Üretim ortamına geçmeden önce mutlaka şu senaryoları test edin: Tek node kaybı, iki node kaybı, tam cluster restart ve network bölünmesi. Bu testleri gece üç’te değil, mesai saatlerinde ve hazırlıklıyken yapın. Galera güvenilir bir teknoloji ama onu tanımak ve davranışlarını önceden bilmek, gerçek kriz anlarında sakin kalmanızı sağlar.

Yorum yapın