İçeriğe geç
Çılgın Yazılım

Veritabanı ve Performans

Veritabanı Göçlerini Sıfır Kesintiyle Uygulamak

Sütun silmek tek satırlık bir iştir; yayındaki uygulamayı düşürmeden silmek ise üç aşamalı bir plan gerektirir.

Çılgın Yazılım 4 dk okuma

Veritabanı Göçlerini Sıfır Kesintiyle Uygulamak
İçindekiler
  1. Asıl sorun: kod ve şema aynı anda değişemez
  2. Genişlet – Taşı – Daralt yöntemi
  3. 1. Genişlet
  4. 2. Çift yazma
  5. 3. Geri doldurma
  6. 4. Okumayı çevir
  7. 5. Daralt
  8. Hangi işlemler tabloyu kilitler?
  9. İndeks eklemenin özel durumu
  10. Göçleri geri alınabilir yazmak
  11. Kontrol listesi
  12. Sonuç

Veritabanı Göçlerini Sıfır, bu yazıda ele aldığımız konunun tam merkezinde yer alıyor; aşağıdaki başlıklarda konuyu uygulanabilir adımlarla ele alıyoruz.

Veritabanı göçü, geliştirme ortamında saniyeler süren ama üretimde uygulamayı dakikalarca erişilemez hâle getirebilen ender işlerden biridir. Bir sütunu yeniden adlandıran tek satırlık bir komut, milyonlarca satırlık bir tabloda tabloyu kilitleyip tüm istekleri kuyruğa alabilir. Bu yazıda yayındaki bir sistemde şema değiştirmenin güvenli yöntemini adım adım ele alıyoruz.

Sıfır kesintili şema göçü aşamaları
Her aşama ayrı bir dağıtımdır; ikisini birleştirmek kesintinin en sık sebebidir.

Asıl sorun: kod ve şema aynı anda değişemez

Kesintisiz dağıtım yapan her sistemde, kısa bir süre için eski kod ile yeni kod aynı anda çalışır. Kademeli yayın sırasında sunucuların yarısı eski sürümü, yarısı yenisini çalıştırır. Bu durumda şema, her iki sürümle de uyumlu olmak zorundadır. "Sütunu yeniden adlandırdım ve kodu güncelledim" diyen tek adımlık bir dağıtım, eski kodun hâlâ eski sütun adını arayacağı o birkaç dakikada hata üretir.

Bu yüzden şema değişiklikleri, kod değişikliklerinden ayrı ve daha yavaş ilerlemelidir. Kural şudur: her göç adımı, hem bir önceki hem de bir sonraki kod sürümüyle çalışabilmelidir.

Genişlet – Taşı – Daralt yöntemi

Sütun yeniden adlandırma örneğiyle gidelim: musteri_adi alanını ad ve soyad olarak ayırmak istiyorsunuz.

1. Genişlet

Yeni sütunları ekleyin, eskisine dokunmayın. Yeni sütunlar NULL kabul etmeli, çünkü mevcut kayıtlar için değer yok. Bu adım geriye tamamen uyumludur ve tek başına yayınlanabilir.

2. Çift yazma

Uygulamayı, yeni kayıtlarda hem eski hem yeni sütunları dolduracak şekilde güncelleyin. Bu aşamadan sonra yeni veriler her iki formatta da mevcuttur.

3. Geri doldurma

Eski kayıtları toplu UPDATE ile değil, parçalar hâlinde taşıyın. Tek bir komutla milyonlarca satırı güncellemek, uzun süren bir işlem (transaction) yaratır, çoğaltma gecikmesini büyütür ve kilitlenmelere yol açar. Bunun yerine birincil anahtara göre 1.000-5.000'lik gruplar hâlinde ilerleyen bir toplu iş yazın ve gruplar arasında kısa bir bekleme koyun.

4. Okumayı çevir

Uygulama artık yeni sütunlardan okusun. Eski sütun hâlâ dolduruluyor; bir sorun çıkarsa geri dönmek tek satırlık bir değişikliktir.

5. Daralt

Kodda eski sütuna hiçbir referans kalmadığını doğruladıktan sonra, çift yazmayı durdurun ve son bir dağıtımda sütunu düşürün. Bu adımı en az bir hafta bekletmek yaygın ve makul bir pratiktir.

Hangi işlemler tabloyu kilitler?

Modern MySQL sürümlerinin çoğu şema değişikliğini yerinde (in-place) ve eşzamanlı yazmaya izin vererek yapabilir, ancak istisnalar önemlidir. Sütun tipini değiştirmek, birincil anahtarı değiştirmek veya karakter kümesini dönüştürmek genellikle tablonun tamamen yeniden yazılmasını gerektirir. Bu sırada tablo boyutu kadar ek disk alanı da tüketilir — diski dolu bir sunucuda göç, kesintiden daha kötü bir sonuç doğurabilir.

Uygulamadan önce her zaman şunu yapın: değişikliği üretim verisinin bir kopyası üzerinde çalıştırıp süresini ölçün. Beş milyon satırlık bir tabloda 40 saniye süren bir işlem, kabul edilebilir bir bakım penceresine sığabilir; sekiz dakika sürüyorsa farklı bir yönteme (örneğin gölge tablo ve tetikleyicilerle çalışan çevrimiçi şema değişikliği araçlarına) ihtiyacınız var demektir.

İndeks eklemenin özel durumu

Yavaş bir sorguyu düzeltmek için indeks eklemek en sık yapılan göçlerden biridir. İndeks oluşturma çoğu durumda okumayı engellemez ama yazmaları yavaşlatır ve büyük tablolarda uzun sürer. Bu yüzden indeks göçlerini yoğun saatlerde değil, trafiğin düşük olduğu bir pencerede planlamak gerekir. Ayrıca eklemeden önce indeksin gerçekten kullanılacağını doğrulamak şarttır; sorgu planı okumayı bilmiyorsanız EXPLAIN nasıl okunur yazımız ve temel mantık için indeks mantığı yazımız iyi bir başlangıçtır.

Göçleri geri alınabilir yazmak

Her göç dosyasında bir geri alma (down) adımı bulunmalıdır — ama burada dürüst olmak gerekir: veri kaybettiren bir göç gerçekten geri alınamaz. Bir sütunu sildiğinizde geri alma adımı sütunu geri ekleyebilir, ama içindeki veriyi geri getiremez. Bu yüzden yıkıcı adımları ayrı göç dosyalarında tutmak ve bunları ancak geri dönüş ihtimalinin kalmadığından emin olduktan sonra çalıştırmak gerekir.

Pratik bir kural: ekleyen göçler otomatik dağıtımda, silen göçler elle onayla çalışsın. Bu ayrım, gece yarısı yapılan bir dağıtımın veri kaybına dönüşmesini engeller.

Ayrıca göç dosyalarının çerçevenizin taradığı doğru dizinde bulunduğundan emin olun; yanlış klasördeki bir göç sessizce hiç çalışmaz ve tablo üretimde eksik kalır. Yayın sürecini otomatikleştirirken geri alma planının önemi için rollback planı yazımıza bakabilirsiniz.

Kontrol listesi

  • Göç, hem eski hem yeni kod sürümüyle uyumlu mu?
  • Üretim boyutundaki bir kopyada süresi ölçüldü mü?
  • Geri doldurma parçalara bölündü mü, tek dev UPDATE değil mi?
  • Yıkıcı adım ayrı bir dosyada ve elle onaylı mı?
  • Çoğaltma (replikasyon) gecikmesi izleniyor mu?
  • Diskte tablo boyutu kadar boş alan var mı?

MySQL'in hangi şema işlemlerini çevrimiçi yapabildiğine dair kesin liste sürüme göre değiştiği için, uygulamadan önce MySQL çevrimiçi DDL dokümantasyonunu kontrol etmek en güvenli yoldur.

Sonuç

Sıfır kesintili veritabanı göçünün sırrı karmaşık araçlarda değil, değişikliği küçük ve geriye uyumlu adımlara bölmekte yatar. Genişlet, çift yaz, geri doldur, okumayı çevir, daralt — beş adımın her biri tek başına güvenlidir ve tek başına geri alınabilir. Bu adımları tek bir dağıtımda birleştirmek, sahada gördüğümüz göç kaynaklı kesintilerin neredeyse tamamının sebebidir. Bir sonraki şema değişikliğinizde kendinize tek bir soru sorun: bu göç uygulandıktan sonra, eski kod sürümü hâlâ çalışabilir mi? Cevap hayırsa, göçü ikiye bölmeniz gerekiyor demektir.

Beğeniniz benzer içerikleri öne çıkarmamıza yardımcı olur.

Sık sorulan sorular

Küçük tablolarda da bu kadar dikkatli olmalı mıyım?

Birkaç bin satırlık tablolarda kilitlenme süresi ihmal edilebilir; ancak eski ve yeni kodun bir arada çalışması sorunu tablo boyutundan bağımsızdır ve orada da geçerlidir.

Bakım penceresi ilan etmek yerine neden bu yöntem?

Bakım penceresi meşru bir seçenektir ve bazen en ucuz yoldur. Ancak sık dağıtım yapan ekiplerde her şema değişikliği için kesinti ilan etmek sürdürülebilir değildir ve zamanla değişiklikleri ertelemeye yol açar.

Geri doldurma işlemi ne kadar sürmeli?

Süre değil, etki önemlidir. Çoğaltma gecikmesi ve sorgu yanıt süreleri izlenerek parça boyutu ayarlanmalı; sistem etkileniyorsa parça küçültülüp bekleme artırılmalıdır.

ORM'in otomatik ürettiği göçlere güvenebilir miyim?

Üretilen SQL'i her zaman gözden geçirin. ORM araçları genellikle en kısa yolu üretir; bu, üretimde tabloyu yeniden yazan bir komut olabilir.

Yazan

Çılgın Yazılım

Ben Evren Çılgın; yazılım geliştirme, web teknolojileri ve sistem tasarımı alanlarında uzmanlaşmış bir geliştiriciyim. Uzun yıllardır hem frontend hem de backend tarafında üretken, ölçeklenebilir ve kullanıcı dostu çözümler üretiyorum.

Hakkımızda Bize ulaşın

Bu konuda bir projeniz mi var?

İhtiyacınızı birkaç cümleyle anlatın; uygun yaklaşımı birlikte belirleyelim.

Projenizi Anlatın

İlgili yazılar

Yorumlar

Henüz yorum yok. Sorunuzu ya da deneyiminizi ilk siz yazın.

Yorum yazın

Yorumunuz onaylandıktan sonra yayınlanır. Ekibimiz gerekirse konuyla ilgili bir yanıt da paylaşır.

Yayınlanmaz; yalnızca gerektiğinde size ulaşmak için.

En az 10 karakter.

Tüm yazılar