sunucu.com.tr
Linux Sunucular

MySQL veritabanı kopyalama ve klonlama: mysqldump ile tutarlı kopya, uzak sunucuya aktarım ve geri yükleme doğrulaması

MySQL veritabanını aynı sunucuda klonlamak ya da başka sunucuya kopyalamak için mysqldump adımları: --single-transaction ile tutarlı döküm, saklı yordam ve olayları dahil etme, büyük veritabanları, SSH ile aktarım, MariaDB sandbox satırı uyumsuzluğu ve kopyanın doğrulanması.

Güncellendi: 9 dk okuma

Bir veritabanına şema değişikliği, toplu güncelleme ya da sürüm yükseltmesi gibi riskli bir işlem yapmadan önce kopyasını almak, işler ters gittiğinde dakikalar içinde geri dönmenizi sağlar. Kopya aynı sunucuda test ortamı kurmak ya da veritabanını yeni bir sunucuya taşımak için de kullanılır.

Bu rehberde Linux sunucuda mysqldump ile MySQL veritabanı kopyalamayı adım adım anlatıyoruz: tek satırlık klonlamanın neden yetmeyebileceğini, tutarlı döküm için gereken seçenekleri, büyük veritabanlarında dikkat edilecekleri, uzak sunucuya aktarımı, MariaDB ile MySQL arasındaki bir uyumluluk sorununu ve kopyanın gerçekten eksiksiz olduğunu nasıl kontrol edeceğinizi göreceksiniz.

Tek satırlık klonlama ve eksikleri

En sade haliyle bir veritabanını aynı sunucuda başka bir veritabanına kopyalamak şöyle yapılır:

bash
mysqldump sunucu_eski | mysql sunucu_yeni

Bu komut çalışır, ama seçeneksiz kullanıldığında bazı açıklar bırakır:

  • Saklı yordamlar ve fonksiyonlar dökülmez. Uygulamanız stored procedure ya da function kullanıyorsa kopyada bunlar olmaz.
  • Zamanlanmış olaylar (events) dökülmez. Event Scheduler ile çalışan işler kopyaya taşınmaz.
  • Tutarlılık garanti değildir. Döküm sürerken uygulama veri yazmaya devam ediyorsa, farklı tablolar farklı anlara ait veriyle dökülebilir. Siparişler tablosu ile sipariş satırları tablosu birbirini tutmayabilir.
  • Hedef veritabanı önceden yoksa komut hata verir ve karakter kümesi kaynakla aynı olmayabilir.

Tetikleyiciler (triggers) varsayılan olarak döküme dahildir, ama yordamlar ve olaylar için ayrıca seçenek vermeniz gerekir. Aşağıdaki adımlar bu açıkları kapatır.

Adım 1: Kimlik bilgilerini güvenli tutun

Parolayı komut satırına -pParola biçiminde yazmak, parolanın kabuk geçmişinde ve süreç listesinde görünmesine yol açar. Bunun yerine kullanıcının ev dizininde bir istemci yapılandırma dosyası kullanın:

ini
# ~/.my.cnf
[client]
user=yedek_kullanici
password=GucluBirParola
bash
chmod 600 ~/.my.cnf

Döküm alacak kullanıcının en az SELECT, SHOW VIEW, TRIGGER, EVENT ve LOCK TABLES yetkilerine sahip olması gerekir. Saklı yordamları dökmek için de bu nesneleri okuyabilecek yetki gerekir. Root ile çalışıyorsanız bu konuda sorun yaşamazsınız, ama düzenli yedek için ayrı ve kısıtlı bir kullanıcı daha güvenlidir.

Adım 2: Hedef veritabanını kaynakla aynı karakter kümesiyle oluşturun

Önce kaynak veritabanının karakter kümesini ve sıralama kuralını öğrenin:

sql
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'sunucu_eski';

Çıkan değerlerle hedefi oluşturun (aşağıdaki değerler örnektir, kendi sonucunuzu yazın):

sql
CREATE DATABASE sunucu_yeni
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

Kontrol noktası: SHOW CREATE DATABASE sunucu_yeni; çıktısı kaynakla aynı karakter kümesini göstermeli. Farklı karakter kümesi, Türkçe karakterlerin bozulmasının en yaygın nedenlerinden biridir.

Adım 3: Tutarlı döküm için doğru seçenekler

Aynı sunucuda klonlama için önerilen komut:

bash
mysqldump --single-transaction --quick \
  --routines --events --triggers \
  sunucu_eski | mysql sunucu_yeni

Seçeneklerin ne işe yaradığı:

Seçenek Ne yapar
--single-transaction Dökümü tek bir işlem (transaction) içinde başlatır; işlemli tablolar döküm başladığı anki haliyle tutarlı alınır ve tablolar uzun süre kilitlenmez.
--quick Satırları belleğe toplamadan tek tek okuyup yazar; büyük tablolarda bellek tüketimini düşük tutar.
--routines Saklı yordam ve fonksiyonları döküme ekler.
--events Zamanlanmış olayları döküme ekler.
--triggers Tetikleyicileri ekler (varsayılan olarak açıktır, açıkça yazmak niyeti belgelemek içindir).

--single-transaction hakkında iki önemli not:

  1. Tutarlı anlık görüntü yalnız işlem destekleyen depolama motorlarında (InnoDB) sağlanır. MyISAM gibi işlem desteklemeyen motorlarda tablolar döküm sırasında değişebilir. Hangi motoru kullandığınızı şu sorguyla görün:
sql
SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'sunucu_eski' AND ENGINE <> 'InnoDB';

Sorgu boş dönüyorsa sorun yok. MyISAM tablolarınız varsa, ya dökümü uygulamanın yazmadığı bir bakım penceresinde alın ya da bu tabloları InnoDB'ye çevirmeyi planlayın.

  1. Döküm sürerken ALTER TABLE, DROP TABLE, TRUNCATE gibi şema değiştiren komutlar çalıştırmayın. Bu komutlar tutarlı okumayı bozabilir ve dökümün hatalı ya da eksik çıkmasına yol açabilir. Şema değişikliğini dökümden sonraya bırakın.

Ayrıntılar için MySQL resmi mysqldump belgesine bakabilirsiniz.

Adım 4: Büyük veritabanlarında dökümü dosyaya alın

Birkaç GB'ı aşan veritabanlarında boru hattıyla (pipe) doğrudan aktarım yerine önce sıkıştırılmış bir dosyaya döküm almak daha kontrollüdür. Böylece aktarım yarıda kesilirse dökümü yeniden almanız gerekmez ve elinizde bir yedek dosyası kalır.

Önce yer olup olmadığına bakın. Veritabanının diskte kapladığı alanı şöyle hesaplayın:

sql
SELECT ROUND(SUM(DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024) AS boyut_mb
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'sunucu_eski';
bash
df -h /yedek

Sıkıştırılmış döküm genellikle veritabanından küçüktür, ama geri yüklemede hedef veritabanı en az kaynak kadar yer kaplayacaktır. Disk dolarsa hem döküm yarım kalır hem de çalışan MySQL durabilir; bunu önceden haber almak için disk doluluk uyarısı betiği kurabilirsiniz.

Dökümü uzun sürebileceği için tmux ya da screen oturumu içinde başlatın, SSH bağlantınız koparsa işlem devam etsin:

bash
tmux new -s dokum
mysqldump --single-transaction --quick \
  --routines --events --triggers \
  sunucu_eski | gzip > /yedek/sunucu_eski_$(date +%F).sql.gz

İlerlemeyi görmek isterseniz pv aracını araya ekleyebilirsiniz:

bash
mysqldump --single-transaction --quick --routines --events \
  sunucu_eski | pv | gzip > /yedek/sunucu_eski.sql.gz

Kontrol noktası: döküm bittiğinde dosyanın sonunda -- Dump completed satırı olmalı. Bu satır yoksa döküm yarıda kesilmiştir:

bash
zcat /yedek/sunucu_eski.sql.gz | tail -n 1

Dosyayı geri yüklemek için:

bash
zcat /yedek/sunucu_eski.sql.gz | mysql sunucu_yeni

Dökümü uygulamanın yoğun olduğu saatlerde almak disk okumasını artırır ve sitenizi yavaşlatabilir. Mümkünse trafiğin düşük olduğu bir saati seçin.

Adım 5: Veritabanını uzak sunucuya kopyalama

Veritabanını başka bir sunucuya taşırken MySQL portunu (3306) internete açmanıza gerek yoktur. Dökümü SSH tüneli üzerinden göndermek hem daha güvenli hem de daha basittir.

Hedef sunucuda boş veritabanını Adım 2'deki gibi oluşturduktan sonra kaynak sunucuda şunu çalıştırın:

bash
mysqldump --single-transaction --quick --routines --events \
  sunucu_eski | gzip | \
  ssh kullanici@hedef-sunucu "gunzip | mysql sunucu_yeni"

Burada döküm kaynakta sıkıştırılır, SSH üzerinden şifreli gider ve hedefte açılıp doğrudan içe aktarılır. Hedef sunucuda da ~/.my.cnf dosyasının hazır olması gerekir, aksi halde mysql parola sorar ve boru hattı takılır.

Bağlantının kopma riski olan uzun aktarımlarda iki aşamalı yöntem daha güvenlidir:

bash
# Kaynakta dosyaya döküm (Adım 4), ardından kopyalama
rsync -avP /yedek/sunucu_eski.sql.gz kullanici@hedef-sunucu:/yedek/

# Hedefte bütünlük kontrolü ve içe aktarma
gzip -t /yedek/sunucu_eski.sql.gz && zcat /yedek/sunucu_eski.sql.gz | mysql sunucu_yeni

rsync -P yarıda kalan aktarımı kaldığı yerden sürdürebilir. gzip -t dosyanın bozulmadan geldiğini doğrular.

Güvenlik duvarı uyarısı: Aktarım için güvenlik duvarında kural değiştirecekseniz, önce SSH portunuza izin veren kuralın yerinde olduğundan emin olun. Yanlış sırada eklenen bir kural kendi SSH erişiminizi keser ve sunucuya yalnız panel konsolundan ulaşabilirsiniz. MySQL portunu açmanız gerekiyorsa yalnız kaynak sunucunun IP adresine açın ve iş bitince kuralı kaldırın.

Veritabanını yeni bir bulut sunucuya taşıyorsanız, uygulama bağlantı ayarlarını değiştirmeden önce aşağıdaki doğrulama adımlarını hedef sunucuda tamamlayın.

MariaDB ve MySQL arasında kopyalama: sandbox satırı sorunu

MariaDB tarafında döküm aracı mariadb-dump adını taşır ve komut seçenekleri büyük ölçüde mysqldump ile aynıdır. Ancak MariaDB'den MySQL'e kopyalarken bilmeniz gereken bir uyumluluk değişikliği var.

MariaDB 10.11.8 sürüm notlarına göre, 16 Mayıs 2024'te yayımlanan bu sürümden itibaren mariadb-dump her döküm dosyasının en başına bir sandbox komutu ekler. Bu satır şu biçimdedir:

sql
/*!999999\- enable the sandbox mode */

MariaDB'nin uyumluluk duyurusuna göre bu satır şu sürümlerle alınan dökümlerde bulunur: 10.5.25, 10.6.18, 10.11.8, 11.0.6, 11.1.5, 11.2.4 ve 11.4.2. Sorun şudur:

  • MySQL komut satırı istemcisi bu komutu yorumlayamaz ve içe aktarma hata vererek durur.
  • 10.5.24 gibi daha eski MariaDB hata düzeltme sürümleri ve 10.4 gibi desteği bitmiş sürümler de bu satırı işleyemez.
  • MySQL istemcisi dışındaki içe aktarma yöntemleri bundan etkilenmez.

Yani güncel bir MariaDB sunucusundan aldığınız dökümü MySQL sunucusuna mysql istemcisiyle yüklemeye çalışırsanız ilk satırda hata alırsınız.

Çözüm

MariaDB'nin önerdiği geçici çözüm, sandbox satırını döküm çıktısından çıkarmaktır. Bunu döküm dosyasını değiştirmeden, içe aktarırken akış üzerinde yapabilirsiniz:

bash
zcat /yedek/maria_dokum.sql.gz | \
  sed '1{/enable the sandbox mode/d}' | \
  mysql hedef_veritabani

Bu komut yalnız ilk satırı ve yalnız sandbox ifadesini içeriyorsa siler; dökümün geri kalanına dokunmaz. Aynı işlemi yedek alırken de yapabilirsiniz:

bash
mariadb-dump --single-transaction --quick --routines --events \
  kaynak_db | sed '1{/enable the sandbox mode/d}' | gzip > /yedek/kaynak_db.sql.gz

Önce ilk satırı kontrol etmek isterseniz:

bash
zcat /yedek/maria_dokum.sql.gz | head -n 1

MariaDB'nin kalıcı çözüm olarak önerdiği yol ise içe aktarmayı bu değişikliği içeren güncel ve güvenli bir MariaDB istemcisiyle yapmaktır. Hedef MariaDB ise istemciyi güncel tutmak yeterlidir; hedef MySQL ise yukarıdaki satır çıkarma yöntemi pratik çözümdür.

MariaDB ile MySQL arasında kopyalamada sandbox satırı dışında da farklar çıkabilir: bir tarafa özgü veri tipleri, depolama motorları ya da sözdizimi hedefte hata verebilir. Bu yüzden karma ortamlarda doğrulama adımını atlamayın.

Adım 6: Kopyayı doğrulayın

İçe aktarma komutunun hatasız bitmesi kopyanın eksiksiz olduğunu göstermez. Şu kontrolleri hem kaynakta hem hedefte çalıştırıp sonuçları karşılaştırın.

1. Tablo sayısı:

sql
SELECT COUNT(*) FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'sunucu_eski';

2. Yordam, fonksiyon, olay ve tetikleyici sayıları:

sql
SELECT ROUTINE_TYPE, COUNT(*) FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA = 'sunucu_eski' GROUP BY ROUTINE_TYPE;

SELECT COUNT(*) FROM information_schema.EVENTS WHERE EVENT_SCHEMA = 'sunucu_eski';
SELECT COUNT(*) FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = 'sunucu_eski';

3. Satır sayıları: information_schema.TABLES içindeki TABLE_ROWS değeri InnoDB'de tahminidir, karşılaştırma için kullanmayın. Kesin sayı için her tabloda COUNT(*) çalıştıran kısa bir betik kullanın:

bash
#!/usr/bin/env bash
# kullanim: ./satir_say.sh veritabani_adi
DB="$1"
for t in $(mysql -N -e "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='${DB}' AND TABLE_TYPE='BASE TABLE' ORDER BY TABLE_NAME"); do
  printf '%s\t%s\n' "$t" "$(mysql -N -e "SELECT COUNT(*) FROM \`${DB}\`.\`${t}\`")"
done
bash
./satir_say.sh sunucu_eski > kaynak.txt
./satir_say.sh sunucu_yeni > hedef.txt
diff kaynak.txt hedef.txt && echo "Satir sayilari ayni"

Uzak kopyada betiği iki sunucuda ayrı çalıştırıp dosyaları karşılaştırın. Kaynakta uygulama yazmaya devam ediyorsa küçük farklar normaldir; karşılaştırmayı yazma durdurulmuşken yapın.

4. İçerik kontrolü: Kritik tablolar için CHECKSUM TABLE iki tarafta aynı sonucu vermelidir. Aynı sunucu sürümü ve aynı satır biçiminde karşılaştırma anlamlıdır; farklı sürümler arasında değerler farklı çıkabilir, bu durumda satır sayısı ve örnek kayıt kontrolüyle yetinin.

sql
CHECKSUM TABLE sunucu_eski.siparisler;
CHECKSUM TABLE sunucu_yeni.siparisler;

5. Uygulama testi: Son kontrol, uygulamanın test kopyasını yeni veritabanına bağlayıp oturum açma, kayıt ekleme ve raporlama gibi temel işlemleri denemektir.

Sık yapılan hatalar

  • --routines ve --events seçeneklerini unutmak. Kopya çalışıyor görünür, ama zamanlanmış işler ve yordamlar sessizce eksik kalır.
  • DEFINER hatası. Görünüm, yordam ve tetikleyiciler döküme oluşturan kullanıcıyla (DEFINER) yazılır. Hedefte bu kullanıcı yoksa içe aktarma hata verir ya da nesneler çalışmaz. Çözüm, aynı kullanıcıyı hedefte de oluşturmaktır.
  • GTID satırı hatası. GTID etkin MySQL sunucularından alınan dökümde GTID_PURGED ayarı bulunur ve bu satır başka bir sunucuya yüklemede hata verebilir. Replikasyon kurmuyorsanız dökümü --set-gtid-purged=OFF ile alın.
  • Disk dolması. Dökümün yazıldığı bölüm ya da hedef veritabanının bulunduğu bölüm dolarsa işlem yarım kalır. Başlamadan önce df -h ile kontrol edin.
  • Yarım kalmış dökümü yüklemek. Dosya sonunda -- Dump completed satırı olmadan içe aktarma yapmayın.
  • Dökümü tek kopya olarak aynı sunucuda bırakmak. Sunucu bozulursa döküm de gider. Düzenli yedeğin nasıl kurgulanacağı için 3-2-1 kuralını anlatan yedekleme rehberine, dökümleri sunucu dışına otomatik göndermek için S3 yedekleme rehberine bakabilirsiniz.

Sık sorulan sorular

MySQL veritabanını aynı sunucuda en hızlı nasıl kopyalarım?

Hedef veritabanını kaynakla aynı karakter kümesiyle oluşturup mysqldump --single-transaction --quick --routines --events sunucu_eski | mysql sunucu_yeni komutunu çalıştırmak, aynı sunucuda klonlamanın en pratik yoludur. Süre veritabanı boyutuna, disk hızına ve tablo yapısına bağlıdır; büyük veritabanlarında dökümü önce dosyaya almak daha kontrollüdür.

Döküm alırken site çalışmaya devam edebilir mi?

Tablolarınız InnoDB ise --single-transaction ile döküm sırasında uygulama okumaya ve yazmaya devam edebilir, döküm başladığı anın tutarlı görüntüsünü alır. MyISAM tablolarında bu garanti yoktur. Her durumda döküm sırasında şema değiştiren komutlardan kaçının.

MariaDB dökümünü MySQL'e yüklerken ilk satırda hata alıyorum, neden?

Güncel MariaDB sürümleri dökümün başına enable the sandbox mode ifadeli bir satır ekler ve MySQL istemcisi bu satırı tanımaz. İçe aktarırken sed '1{/enable the sandbox mode/d}' ile ilk satırı akıştan çıkarın ya da içe aktarmayı güncel bir MariaDB istemcisiyle yapın.

Uzak sunucuya kopyalamak için 3306 portunu açmam gerekir mi?

Gerekmez. Dökümü ssh üzerinden boru hattıyla ya da rsync ile dosya olarak gönderebilirsiniz. Böylece veritabanı portu internete kapalı kalır ve veri aktarım boyunca şifreli gider.

Kopyanın eksiksiz olduğunu nasıl anlarım?

İki tarafta tablo, yordam, olay ve tetikleyici sayılarını information_schema üzerinden karşılaştırın, her tablo için COUNT(*) ile kesin satır sayısını alın ve kritik tablolarda CHECKSUM TABLE sonuçlarına bakın. Son olarak uygulamayı test ortamında yeni veritabanına bağlayıp temel işlemleri deneyin.

Yazar

Kurucu, sunucu.com.tr · Bulut altyapısı ve yapay zeka otomasyonları

sunucu.com.tr ve Sunucu UK'in kurucusu. Bulut altyapısı, sanallaştırma ve sunucu yönetimi üzerine çalışıyor; şirketlerin iş yazılımlarını, web sitelerini ve yapay zeka iş yüklerini güvenli sunuculara taşıyor. Blogdaki rehberler sahada karşılaşılan kurulum, güvenlik ve taşıma işlerinden derlenir; yazılar yapay zeka desteğiyle hazırlanır ve kaynaklarla doğrulanır.

Tüm yazılarıProfil