Geliştirme ortamında iki saniyede biten bir ALTER TABLE, üretimdeki 80 milyon satırlık tabloda 40 dakika sürer ve o 40 dakika boyunca site cevap vermez. Bunu bir kez yaşayan herkes, bir daha üretimde doğrudan ALTER TABLE çalıştırmaktan çekinir — ama şema da bir yerde değişmek zorundadır. Kesintisiz büyük tablo migrasyonu, tam olarak bu ikilemi çözen tekniğin adıdır: tabloyu kilitlemeden, siteyi durdurmadan, arka planda kopyalayarak şemayı değiştirmek.
Bu rehberde önce normal ALTER TABLE'ın neden ve tam olarak nerede kilitlendiğini, MySQL'in kendi çevrimiçi DDL yeteneğinin nereye kadar yettiğini göstereceğim. Ardından Percona Toolkit'in pt-online-schema-change aracını çalışma mantığıyla birlikte adım adım kullanacağız; GitHub'ın tetikleyicisiz alternatifi gh-ost ile farklarını, replikasyonlu ortamlarda dikkat edilecekleri, yabancı anahtar tuzağını ve geri alma planını da ele alacağım.
Normal ALTER TABLE Neden Yetmiyor#
Klasik ALTER TABLE, birçok işlem türünde tablonun tamamını yeni bir dosyaya kopyalar. Kopyalama sırasında tablo yazmaya kapalıdır; okuma bazı durumlarda devam eder ama yazmaya çalışan her bağlantı kuyruğa girer. Kuyruk büyüdükçe uygulama bağlantı havuzu dolar, ardından tüm site cevapsız kalır — yani sorun tablonun kilitlenmesi değil, kilidin uygulamaya yayılmasıdır.
İkinci ve daha sinsi sorun, metadata kilididir. ALTER TABLE başlamak için tablo üzerinde çalışan tüm işlemlerin bitmesini bekler. Uzun süren tek bir SELECT varsa ALTER bekler; ALTER beklerken arkasında biriken tüm yeni sorgular da bekler. Sonuç, kimsenin beklemediği bir kilitlenme zinciridir:
-- Bekleyen metadata kilitlerini görmek
SELECT id, user, host, db, command, time, state, LEFT(info, 60) AS sorgu
FROM information_schema.processlist
WHERE state LIKE '%metadata lock%' OR command = 'Query'
ORDER BY time DESC;
Ne kadar süreceğini kabaca kestirmek için tablo boyutuna ve disk hızına bakılır. Pratik bir tahmin tablosu:
| Tablo boyutu | Kopyalama tipi ALTER (NVMe) | Kabul edilebilir mi |
|---|---|---|
| < 100 MB | Saniyeler | Evet, doğrudan çalıştırın |
| 1 GB | 1-3 dakika | Bakım penceresinde |
| 10 GB | 10-30 dakika | Hayır, çevrimiçi araç kullanın |
| 100 GB+ | Saatler | Kesinlikle çevrimiçi araç |
MySQL'in Kendi Çevrimiçi DDL Yeteneği#
Her şema değişikliği için harici araç gerekmez. MySQL 5.6'dan itibaren birçok işlem yerinde (INPLACE) yapılabilir ve MySQL 8'de bazı işlemler anlık (INSTANT) tamamlanır. Doğru yaklaşım, önce bunu denemektir; yeterse en basit ve en hızlı yol budur.
-- Anlık: yalnızca veri sözlüğü güncellenir, tablo kopyalanmaz
ALTER TABLE siparisler
ADD COLUMN kaynak VARCHAR(32) NULL,
ALGORITHM=INSTANT;
-- Yerinde ve kilitsiz: indeks ekleme genelde bu şekilde çalışır
ALTER TABLE siparisler
ADD INDEX idx_durum_tarih (durum, olusturma_tarihi),
ALGORITHM=INPLACE, LOCK=NONE;
Buradaki en önemli alışkanlık, algoritmayı açıkça belirtmektir. ALGORITHM=INPLACE, LOCK=NONE yazdığınızda MySQL bu işlemi yerinde yapamıyorsa hata verir ve çalıştırmaz; belirtmezseniz sessizce kopyalama moduna düşer ve siteyi durdurur. Yani açık belirtim bir güvenlik kemeridir:
-- Bu, kopyalama gerektirir; hata alırsınız, üretim durmaz
ALTER TABLE siparisler MODIFY tutar DECIMAL(12,2) NOT NULL,
ALGORITHM=INPLACE, LOCK=NONE;
-- ERROR: ALGORITHM=INPLACE is not supported. Reason: ...
Yerinde yapılamayan tipik işlemler şunlardır: kolon veri tipini değiştirmek, birincil anahtarı değiştirmek, kolon sırasını değiştirmek, karakter setini dönüştürmek, tablo motorunu değiştirmek. Bu durumlarda sıra çevrimiçi şema değişikliği araçlarına gelir. Ayrıca sürüm yükseltmeleri sırasında da benzer kararlar verirsiniz; süreç için MySQL 5.7'den 8.4'e yükseltme yazısına bakabilirsiniz.
pt-online-schema-change Nasıl Çalışır#
Percona Toolkit'in bu aracı, işi şu beş adımda yapar ve mantığını bilmek kullanırken güven verir:
- Orijinal tablonun boş bir kopyasını
_tablo_newadıyla oluşturur. - İstediğiniz
ALTERifadesini bu boş tabloya uygular; boş olduğu için anlık biter. - Orijinal tabloya üç tetikleyici (
INSERT,UPDATE,DELETE) ekler; böylece kopyalama sürerken gelen tüm değişiklikler yeni tabloya da yazılır. - Satırları küçük parçalar halinde kopyalar; her parçadan sonra sunucu yüküne bakıp gerekirse yavaşlar.
- Kopyalama bitince tabloları atomik bir
RENAMEile değiştirir ve tetikleyicileri kaldırır.
Kesintinin yalnızca son adımdaki RENAME işlemi kadar sürmesinin sebebi budur; o da milisaniyeler alır. Kurulumu paket yöneticisinden yapılır:
# Debian/Ubuntu
sudo apt install -y percona-toolkit
pt-online-schema-change --version
Aracın en değerli tarafı, yük farkındalığıdır. --max-load ile belirlediğiniz eşiği aştığında kopyalamayı duraklatır, --critical-load eşiğinde ise tamamen durur. Böylece migrasyon, yoğun saatte siteyi devirmek yerine kendi kendini yavaşlatır.
Adım Adım Güvenli Çalıştırma#
Sıra şudur ve atlanacak adım yoktur:
- Yedek alın. Migrasyon geri alınabilir olsa da, önce yedek. Yöntem için mysqldump ile veritabanı yedekleme yazısına bakın.
- Disk alanını kontrol edin. Araç tablonun tam bir kopyasını oluşturur; boş alan tablo boyutunun en az bir katı kadar olmalıdır.
- Kuru çalıştırma yapın.
--dry-runhiçbir şey değiştirmeden ne yapacağını söyler. - Gerçek çalıştırmayı
--executeile yapın, yük eşiklerini vererek. - İzleyin. İlerlemeyi ve replika gecikmesini takip edin.
- Doğrulayın. Yeni şemayı ve satır sayısını kontrol edin.
# 3. adım: kuru çalıştırma
pt-online-schema-change \
--alter "ADD COLUMN kaynak VARCHAR(32) NULL, ADD INDEX idx_kaynak (kaynak)" \
D=uygulama_db,t=siparisler \
--host=127.0.0.1 --user=migrasyon --ask-pass \
--dry-run
# 4. adım: gerçek çalıştırma, yük korumalı
pt-online-schema-change \
--alter "ADD COLUMN kaynak VARCHAR(32) NULL, ADD INDEX idx_kaynak (kaynak)" \
D=uygulama_db,t=siparisler \
--host=127.0.0.1 --user=migrasyon --ask-pass \
--max-load "Threads_running=25" \
--critical-load "Threads_running=60" \
--chunk-time=0.5 \
--max-lag=5 \
--progress time,30 \
--no-drop-old-table \
--execute
Bu komuttaki üç seçenek özellikle önemlidir. --chunk-time=0.5 aracın parça boyutunu, her parça yaklaşık yarım saniyede kopyalanacak şekilde otomatik ayarlamasını sağlar; sabit satır sayısı vermekten çok daha güvenlidir. --max-lag=5 replika gecikmesi 5 saniyeyi aştığında duraklatır. --no-drop-old-table ise eski tabloyu _tablo_old adıyla saklar — geri dönmeniz gerekirse hayat kurtarır, ancak diski dolu bırakmamak için işlem doğrulandıktan sonra elle silmeyi unutmayın.
--alter ifadesinde tablo adını yazmadığınıza dikkat edin: yalnızca ALTER TABLE sonrasına gelen kısmı yazarsınız, tablo D=...,t=... ile belirtilir. Bu, en sık yapılan sözdizimi hatasıdır.
gh-ost ile Farkları ve Tercih Kriteri#
gh-ost, aynı işi tetikleyici kullanmadan yapar: değişiklikleri binary log'dan okuyup yeni tabloya uygular. Tetikleyici olmaması, orijinal tabloya yazan işlemlere ek yük binmemesi demektir ve çok yoğun yazma alan tablolarda gözle görülür fark yaratır. Ayrıca çalışırken müdahale edilebilir: hızını değiştirebilir, duraklatabilir, geçiş anını (cut-over) elle tetikleyebilirsiniz.
| Ölçüt | pt-online-schema-change | gh-ost |
|---|---|---|
| Çalışma yöntemi | Tetikleyici | Binary log okuma |
| Orijinal tabloya ek yük | Var (her yazmada tetikleyici) | Yok |
| Yabancı anahtar desteği | Sınırlı, dikkatli kullanılır | Desteklenmiyor |
| Tabloda mevcut tetikleyici | Sorun çıkarabilir | Desteklenmiyor |
| Çalışırken müdahale | Sınırlı | Zengin (duraklat, hızlandır, ertele) |
| Gereksinim | Percona Toolkit | ROW biçiminde binlog |
| Kurulum kolaylığı | Paket yöneticisi | Tek ikili dosya |
Seçim kuralı şöyle özetlenebilir: tabloda yabancı anahtar ya da mevcut tetikleyici varsa pt-online-schema-change, yazma trafiği çok yoğunsa ve geçiş anını kontrol etmek istiyorsanız gh-ost. gh-ost ile tipik bir çalıştırma şuna benzer:
gh-ost \
--host=127.0.0.1 --database=uygulama_db --table=siparisler \
--alter="ADD COLUMN kaynak VARCHAR(32) NULL" \
--user=migrasyon --ask-pass \
--allow-on-master \
--max-load="Threads_running=25" \
--critical-load="Threads_running=60" \
--postpone-cut-over-flag-file=/tmp/gh-ost.bekle \
--execute
--postpone-cut-over-flag-file çok kullanışlıdır: kopyalama biter ama geçiş, siz o dosyayı silene kadar yapılmaz. Yani ağır kopyalama işini gündüz yapıp, geçişi gece trafiğin düştüğü ana bırakabilirsiniz.
Replikasyon, Yabancı Anahtarlar ve Diğer Tuzaklar#
Replika gecikmesi. Migrasyon, birincilde milyonlarca satır yazar; bunların hepsi replikalara da gider. Gecikme kontrolü olmadan çalıştırılan bir migrasyon, replikaları saatlerce geride bırakır ve okuma trafiğini oradan alan uygulamalar bayat veri gösterir. --max-lag (ya da gh-ost tarafında kısıtlama seçenekleri) mutlaka kullanılmalıdır. Replikasyon kurulumunun ayrıntıları için MySQL replikasyon kurulumu yazısına bakın.
Yabancı anahtarlar. En büyük tuzak budur. Tablo yeniden adlandırıldığında ona işaret eden yabancı anahtarlar da yönetilmelidir; pt-online-schema-change bunu --alter-foreign-keys-method seçeneğiyle yapar ama seçilen yöntem bazı durumlarda kısa bir kilit ya da kısıtların yeniden oluşturulmasını gerektirir. Bu tabloları migrasyona sokmadan önce mutlaka bir kopyada deneyin:
-- Hangi tablolar bu tabloya yabancı anahtarla bağlı?
SELECT table_name, constraint_name, column_name
FROM information_schema.key_column_usage
WHERE referenced_table_schema = 'uygulama_db'
AND referenced_table_name = 'siparisler';
Disk alanı. Kopya tablo, orijinalin yanında büyür. 80 GB'lık bir tabloda migrasyon sırasında en az 80 GB daha boş alana ihtiyacınız vardır; --no-drop-old-table kullanıyorsanız bu alan işlem sonrasında da bir süre dolu kalır. Disk dolarsa migrasyon yarıda kalır ve geride tetikleyicilerle birlikte yarım bir tablo bırakır.
Mevcut tetikleyiciler. Tabloda zaten tetikleyici varsa pt-online-schema-change eski MySQL sürümlerinde çalışmaz; MySQL 8 birden çok tetikleyiciye izin verse de bu durumda davranışı önceden test etmek şarttır.
Benzersiz anahtar gereksinimi. Her iki araç da satırları eşleştirebilmek için tabloda bir birincil anahtar ya da benzersiz indeks arar. Birincil anahtarı olmayan bir tabloda çalışmazlar; böyle bir tablonuz varsa önce anahtar eklemeniz gerekir ki bu da kendi başına bir migrasyondur.
Geri Alma Planı ve Sık Yapılan Hatalar#
Her migrasyonun yazılı bir geri alma planı olmalıdır. İyi haber şu: bu araçlar geçişten önceki tüm süreçte orijinal tabloya dokunmaz, yani kopyalama aşamasında işlemi durdurmak güvenlidir. Yapılacak tek şey, aracın bıraktığı geçici tabloyu ve tetikleyicileri temizlemektir:
-- Yarıda kalan bir işlemden sonra kalıntı kontrolü
SHOW TABLES LIKE '\_siparisler\_%';
SELECT trigger_name, event_manipulation, event_object_table
FROM information_schema.triggers
WHERE event_object_schema = 'uygulama_db';
Kalıntı tetikleyiciler temizlenmezse orijinal tabloya yapılan her yazma, artık var olmayan bir tabloya yazmaya çalışır ve uygulama hata verir. Bu, yarıda kesilen bir migrasyonun en tehlikeli sonucudur; işlemi durdurduysanız kontrol listesinin ilk maddesi budur.
Geçiş yapıldıktan sonra geri dönmek isterseniz, --no-drop-old-table sayesinde eski tablo hâlâ durur ama o tablo geçiş anından sonraki yazmaları içermez; yani basit bir yeniden adlandırma veri kaybı demektir. Geçiş sonrası geri dönüş, gerçek bir kurtarma işlemidir ve veritabanı felaket kurtarma planı yazısındaki adımlarla ele alınmalıdır.
En sık yapılan hatalar şunlar: kuru çalıştırmayı atlamak, yük eşiklerini vermemek (araç varsayılan olarak da korur ama sizin sisteminizin eşiğini bilmez), yoğun saatte başlatmak, disk alanını kontrol etmemek, --alter içine tablo adını yazmak ve işlemi screen/tmux içinde çalıştırmamak — SSH bağlantısı koptuğunda saatlerdir süren migrasyon da kesilir.
Sıkça Sorulan Sorular#
pt-online-schema-change gerçekten kesintisiz mi#
Neredeyse kesintisiz demek daha doğru olur. Kopyalama boyunca tablo okunabilir ve yazılabilir durumdadır; tek kesinti, en sondaki tablo değiştirme (rename) anıdır ve bu milisaniyeler sürer. Ancak araç arka planda ciddi bir yazma yükü ürettiği için sistem genel olarak yavaşlayabilir; bu yüzden yük eşikleri vermek ve tercihen düşük trafikli saatlerde çalıştırmak gerekir.
Migrasyon ne kadar sürer#
Süre esas olarak tablo boyutuna, disk hızına ve verdiğiniz yük eşiklerine bağlıdır. Kaba bir fikir vermek gerekirse, hızlı NVMe diskte 10 GB'lık bir tablo genellikle onlarca dakika, 100 GB'lık bir tablo birkaç saat sürer. Yük eşiği düşük ayarlandığında araç sık sık duraklayacağı için süre uzar; bu bir sorun değil, bilinçli bir takastır.
gh-ost mu pt-online-schema-change mi kullanmalıyım#
Tabloda yabancı anahtar ya da mevcut tetikleyici varsa gh-ost bunları desteklemediği için pt-online-schema-change kullanmalısınız. Yazma trafiği çok yoğun bir tabloda ve geçiş anını kendiniz kontrol etmek istiyorsanız gh-ost daha iyidir, çünkü tetikleyici yükü getirmez ve çalışırken müdahale imkânı sunar. İkisi de olgun araçlardır; seçim tamamen tablonuzun yapısına bağlıdır.
Küçük tablolarda da bu araçları kullanmalı mıyım#
Hayır, gereksiz karmaşıklık olur. Birkaç yüz megabaytın altındaki tablolarda doğrudan ALTER TABLE çalıştırmak saniyeler sürer. Önce ALGORITHM=INPLACE, LOCK=NONE ekleyerek deneyin; MySQL yapabiliyorsa yapar, yapamıyorsa hata verir ve üretimi durdurmadan sizi uyarır. Çevrimiçi araçlara sıra, ancak bu deneme başarısız olduğunda ya da tablo gerçekten büyük olduğunda gelir.
Migrasyon sırasında sunucu çökerse ne olur#
Orijinal tablo bozulmaz; geride yarım kalmış bir geçici tablo ve tetikleyiciler kalır. Yapmanız gereken, kalıntı tetikleyicileri ve _tablo_new biçimindeki geçici tabloyu temizlemektir. Tetikleyiciler temizlenmezse uygulama, olmayan bir tabloya yazmaya çalışacağı için hata almaya başlar. Temizlik sonrası migrasyonu baştan çalıştırabilirsiniz.
Bu araçlar MariaDB ile çalışır mı#
Evet, pt-online-schema-change MariaDB ile de yaygın biçimde kullanılır. gh-ost binary log okuduğu için sürüm ve yapılandırma uyumuna daha duyarlıdır; kullanmadan önce kendi sürümünüzle bir test ortamında denemeniz gerekir. MariaDB'nin kendi çevrimiçi DDL yetenekleri de zaman içinde gelişti, bu yüzden önce yerinde algoritmayı denemek MariaDB tarafında da doğru ilk adımdır.
Kapanış#
Büyük tablo migrasyonu, aslında bir araç öğrenme işi değil bir disiplin işidir. Aklınızda kalması gereken dört alışkanlık şu: önce ALGORITHM=INPLACE, LOCK=NONE ile deneyip MySQL'in kendi yeteneğini kullanın, çevrimiçi araca geçtiğinizde mutlaka kuru çalıştırma yapın, yük ve replika gecikmesi eşiklerini kendi sisteminize göre verin, ve işlemi kalıcı bir oturumda (screen/tmux) çalıştırıp disk alanını önceden kontrol edin. Yarıda kalan bir migrasyondan sonra ilk bakacağınız yerin kalıntı tetikleyiciler olduğunu da not edin.
Bu tür işlemleri rahatça yürütebileceğiniz, disk ve bellek payı geniş sunucular için VDS ve bulut sunucu paketlerimize bakabilirsiniz; migrasyon öncesi yedeklerin sunucu dışına alınması için yedekleme hizmetimiz devrede. Şema değişikliğini planlamak, bakım penceresini yönetmek ve işlem sırasında sistemi izlemek istemiyorsanız sunucu yönetimi hizmetimiz bu süreci baştan sona üstlenir.