8 dk

Expand/contract deseniyle kesintisiz şema değişiklikleri

Expand/contract deseni, güvenli backfill, uyumlu sürümler, doğrulama ve geri dönüş ile kesintisiz şema değişikliklerini planlayın ve yayınlayın.

Expand/contract deseniyle kesintisiz şema değişiklikleri

Şema değişiklikleri neden kesintiye yol açar

Şema değişiklikleri, uygulama sürümleri, arka plan worker'ları ve veritabanı hangi yapıların ve değerlerin geçerli olduğu konusunda aynı fikirde olmadığında kesintiye yol açar. Sorun, her isteğin hata vermesi kadar açık olabilir. Sorgu gecikmesinin artması, yazmaların başarısız olması, replika gecikmesi ve yeniden oynatılması gereken görevlerin birikmesi gibi yavaş gelişen belirtiler de görülebilir.

Üretim dağıtımı nadiren tüm süreçleri aynı anda değiştirir. Kademeli dağıtımlar eski ve yeni uygulama örneklerini birlikte çalıştırır. Uzun ömürlü worker'lar saatlerce eski sürümü kullanabilir, mobil istemciler aylarca etkin kalabilir; raporlama ve entegrasyon görevleri de ana uygulamadan geçmeden tabloları kullanabilir. Hepsi tek bir veritabanını paylaşır.

Yaygın hata biçimleri şunlardır:

  • Yeni kod, onu oluşturan taşıma tamamlanmadan bir sütuna yazar.
  • Eski kod, sonraki sürümün yeniden adlandırdığı veya kaldırdığı tabloyu ya da sütunu okur.
  • Tablo yeniden yazımı, backfill veya dizin oluşturma normal trafiği yavaşlatacak kadar I/O ve CPU tüketir.
  • Bir şema komutu kilit beklerken istekler onun arkasında birikir.
  • Yeni bir kısıt, henüz yükseltilmemiş bir sürecin yazmalarını reddeder.

Tehlikeli olan çoğu zaman komutun nominal çalışma süresi değil, kilit edinmesidir. Hızlı bir ALTER TABLE, uzun süren bir işlemin arkasında bekleyebilir. Beklerken sonraki sorgular bekleyen şema kilidinin arkasında kuyruk oluşturabilir ve küçük bir taşıma uygulama genelinde duraksamaya dönüşebilir.

Kesintisiz çalışma, aradaki her veritabanı durumunun hâlâ çalışabilecek tüm uygulama sürümleri tarafından kullanılabilmesini gerektirir. Önce uyumlu yapıları ekleyin, trafiği ve veriyi kontrollü adımlarla taşıyın, eski yolu da son tüketicisi ortadan kalktıktan sonra kaldırın.

Bu çalışma, canlı trafiği, kademeli dağıtımları, sıkı erişilebilirlik hedefleri veya pahalı kurtarma prosedürleri olan sistemlerde anlamlıdır. Sessiz bir veritabanına sahip küçük bir iç araç, test edilmiş bir bakım penceresinden daha çok fayda görebilir. Karar, kesintinin maliyetini ve taşımanın operasyonel karmaşıklığını yansıtmalıdır.

Expand/contract'ı sade biçimde açıklamak

Expand/contract deseni, uyumsuz tek bir değişikliği uyumlu sürümler dizisine dönüştürür. Kod ve veri eskiden yeniye taşınırken veritabanı geçici olarak iki gösterimi destekler.

Sıralamanın üç bölümü vardır:

  • Mevcut kodun ihtiyaç duyduğu hiçbir şeyi kaldırmadan sütun, tablo, dizin veya kısıt ekleyerek expand edin.
  • Uyumlu kod yayınlayarak, geçmiş veriyi taşıyarak ve okuma ile yazmaları yeni gösterime yönlendirerek geçiş yapın.
  • Doğrulama, eski nesnelerin kullanılmadığını kanıtladıktan sonra eski kodu ve veritabanı nesnelerini kaldırarak contract edin.

Bir PostgreSQL tablosunun kişinin adını full_name içinde tuttuğunu, uygulamanın ise ayrı first_name ve last_name alanlarına ihtiyaç duyduğunu düşünün. Expand aşamasında full_name korunurken nullable sütunlar eklenir. Uyumlu sürüm, geçişte gereken gösterimleri yazar. Backfill mevcut değerleri ayırır; güvenilir biçimde ayrılamayan adlar için açık bir politika gerekir. Okumalar, yeni alanlar yeterince dolmadan taşınmaz. Contract aşamasında full_name kaldırılır.

Bu sıra kademeli dağıtımlara uygundur, çünkü eski sürüm full_name alanını, yeni sürüm ise üç sütunu da bulur. Uygulama geri dönüş yolunu da korur. Yeni sürüm sorun çıkarırsa önceki sürüm çalışabilir; şema bağımlılıkları kaldırılmamıştır.

Veritabanını geri almak, uygulamayı geri almaktan farklıdır. Veri dönüştürüldükten sonra bir taşımayı tersine çevirmek bilgi kaybına veya eski bir değerin geri gelmesine neden olabilir. Geçişte, eklenmiş veritabanı nesnelerini yerinde bırakıp uygulama trafiğini bilinen gösterime geri döndürmeyi tercih edin. Olay stabil hale geldikten sonra ileri yönlü taşımayı düzeltin.

Bu desen, her değişikliğin çift yazma kodu gerektirdiği anlamına gelmez. Yalnızca yeni kodun kullandığı isteğe bağlı bir sütun, tek bir ekleyici taşıma ve bir dağıtım gerektirebilir. Yeniden adlandırmalar, gösterim değişiklikleri, tablo bölmeleri ve zorunlu alan değişiklikleri genellikle daha çok aşama ister; aksi halde iki uygulama sürümü şemayı güvenle paylaşamaz.

Adımları seçmeden önce değişikliği sınıflandırın

Taşıma planı, işlemin gerçek kilit, yeniden yazım, uyumluluk ve veri dönüştürme riskine uymalıdır. Her ALTER TABLE komutunu eşdeğer saymak, ya gereksiz törenlere ya da güvensiz bir sürüme yol açar.

Ekleyici değişiklikler genellikle en kolay olanlardır. Nullable bir sütun, ayrı bir tablo veya çevrimiçi yöntemle oluşturulmuş dizin, uygulama kodu kullanmadan önce çoğu zaman eklenebilir. Komut yine de kilit ister. Davranışını üretime benzer tablo ve işlem yükü üzerinde test edin.

Yıkıcı değişiklikler sütun kaldırmayı ya da yeniden adlandırmayı, tür daraltmayı, tablo değiştirmeyi ve daha sıkı kısıtlar eklemeyi içerir. Bunlar mevcut kodun varsayımını geçersiz kılar. Kod başvuruları ve dış tüketiciler kaldırıldıktan sonra contract aşamasına koyun.

Veri değiştiren işlemler ayrıca değerlendirilmelidir. Zaman damgalarını dönüştürmek, telefon numaralarını normalleştirmek, kayıtları birleştirmek veya serbest metni bölmek bilgi kaybına yol açabilir. Backfill başlamadan önce geçersiz ve belirsiz değerlerin nasıl ele alınacağını belirleyin. Bir dönüşüm tersine çevrilemiyorsa sonuç iş kuralları düzeyinde kontrolden geçene kadar kaynağı koruyun.

Yararlı bir ön kontrol şu beş soruyu kapsar:

  • Her ifade hangi kilidi ister; bu kilidi ne kadar bekleyebilir veya tutabilir?
  • İşlem tabloyu yeniden yazar mı, ağır WAL üretir mi veya replika gecikmesini artırır mı?
  • Etkilenen nesneleri hangi uygulamalar, görevler, raporlar ve change-data-capture tüketicileri kullanıyor?
  • Mevcut ve önerilen sürümler her geçiş durumunda çalışabilir mi?
  • İşlemi hangi sinyal duraklatır, durduğunda geriye tam olarak hangi durum kalır?

Tam taşıma işlemini gerçekçi hacim ve dağılıma sahip veride çalıştırın. Bin düzgün satırlı test tablosu, yüz milyonlarca satır, geniş tuple'lar, silinmiş satırlar, çarpık değerler ve uzun işlemler içeren üretim tablosu hakkında çok az şey söyler.

PostgreSQL'de güvenli expand

Güvenli PostgreSQL expand işlemi kısa meta veri değişiklikleri, sınırlı kilit beklemeleri ve gerektiğinde ayrı çevrimiçi işlemler kullanır. Yeni yapıyı, ona bağlı kodu dağıtmadan önce ekleyin.

Varsayılanı olmayan nullable bir sütun eklemek genellikle kısa bir meta veri işlemidir:

BEGIN;
SET LOCAL lock_timeout = '2s';
SET LOCAL statement_timeout = '30s';

ALTER TABLE customers
ADD COLUMN phone_e164 text;

COMMIT;

Zaman aşımı, sürümün açık bir işlemin arkasında süresiz beklemesini önler. Kilit hızla alınamıyorsa taşımanın başarısız olmasına izin verin, engelleyeni inceleyin ve daha güvenli bir zamanda yeniden deneyin. Sıkı bir döngüde otomatik tekrar denemeyin; tekrar eden kilit istekleri üretim trafiğini rahatsız etmeyi sürdürebilir.

Güncel PostgreSQL sürümleri, sabit varsayılanı olan bir sütunu mevcut her satıra o değeri hemen yazmadan ekleyebilir. Bu iyileştirme her varsayılanı zararsız kılmaz. Değişken bir ifade yeniden yazım gerektirebilir ve ALTER TABLE yine kısa süreli ACCESS EXCLUSIVE kilidi ister. Genel bir kurala güvenmek yerine, dağıtılmış PostgreSQL sürümünün ve ifadenin tam davranışını doğrulayın.

Normal CREATE INDEX yazmaları engelleyebilir. Tablo yazılabilir kalmalıysa eşzamanlı oluşturmayı kullanın:

CREATE INDEX CONCURRENTLY idx_customers_phone_e164
ON customers (phone_e164);

CREATE INDEX CONCURRENTLY işlem bloğunda çalışamaz. Daha uzun sürer, ek iş yapar ve eski işlemleri bekleyebilir; ancak normal ekleme, güncelleme ve silme işlemleri devam eder. Yine de CPU, I/O ve WAL tüketir; çalışırken veritabanı gecikmesini ve replikaları izleyin.

Başarısız bir eşzamanlı oluşturma, geçersiz bir dizin bırakabilir. Yeniden denemeden önce dizin durumunu inceleyin, ardından geçersiz nesneyi bilinçli biçimde kaldırın veya yeniden oluşturun. Her taşıma dosyasını işlem içine alan araçların, eşzamanlı dizin işlemleri için desteklenen işlemsiz bir moda ihtiyacı vardır.

Yeni tablolar çoğu zaman yerinde dönüşümlerden daha kolay eklenir. Bire çok veya çoğa çok ilişkide, kaynak sütunu korurken hedef tabloyu ve dizinlerini ekleyin. Yeni yazmalar, geçmiş veri, okumalar ve alt tüketiciler taşınana kadar kaynağı silmeyin.

Tür değişiklikleri özel dikkat ister. Bazıları yalnızca meta veri değişikliğidir, bazıları ise her satırı yeniden yazar veya çok uzun süre kısıtlayıcı kilit alır. Riskli dönüşümde hedef türde bir sütun ekleyin, bunu gruplar halinde doldurun, uygulama erişimini değiştirin ve özgün sütunu daha sonra kaldırın. Böylece tek büyük ALTER COLUMN TYPE işleminin topluca başarılı veya başarısız olması yerine dönüşüm hatalarını kaydedecek bir yeriniz olur.

Uyumlu kalan kod dağıtın

Uyumlu uygulama kodu, geçici olarak eksik değerleri tolere eder ve aynı dağıtım sırasında yıkıcı taşıma gerektirmez. İlk uygulama örneği yeni nesneyi kullanmadan önce veritabanı expand işlemi tamamlanmalıdır.

İki gösterimin güncel kalması gerektiğinde çift yazma yararlıdır. Mümkün olduğunda iki yazmayı aynı veritabanı işlemi içinde yapın. Zaman uyumsuz ikinci yazma, ilki başarılı olduktan sonra hata verebilir ve sonraki okumaların ortaya çıkaracağı ayrışma oluşturabilir.

Çift yazma mantığının tek bir otoritesi de olmalıdır. phone_e164, phone alanından türetiliyorsa ikisi de sağlandığında hangisinin öncelikli olduğunu tanımlayın; aynı normalleştirmeyi API işleyicilerinde, worker'larda, içe aktarımlarda ve yönetim araçlarında uygulayın. Aksi halde doğru görünen iki kod yolu farklı sonuçlar saklayabilir.

Okumalar yazmalardan daha sonra taşınmalıdır. Yeni yazmalar iki biçimi de doldururken ve backfill geçmiş satırları işlerken okumaları yerleşik alanda tutun. Doğrulamadan sonra yeni alanı tercih eden, eski değeri yalnızca tanımlı geri dönüş kuralıyla kullanan okuma yolunu dağıtın. Geri dönüş kullanımını ölçün. Sessiz kalan geri dönüş, eksik veriyi sonsuza dek gizleyebilir.

Tipik sürüm sırası şöyledir:

  • Sürüm 1, uygulama davranışını değiştirmeden yeni veritabanı nesnelerini ekler.
  • Sürüm 2, yerleşik okumaları sürdürürken geçiş gösterimlerini yazar.
  • Sürüm 3, backfill ve tutarlılık kontrolleri geçince okumaları değiştirir.
  • Sürüm 4, geri dönüş ölçütleri sona erdikten sonra eski gösterimi güncel tutmayı bırakır.
  • Sürüm 5, eski kod başvurularını kaldırır; veritabanı temizliği daha sonra gelir.

Herkese açık API sözleşmelerini fiziksel şema değişikliklerinden ayırın. Yeniden adlandırılmış veritabanı sütunu, web, mobil veya entegrasyon yanıtlarında alanın hemen yeniden adlandırılmasını gerektirmez. Özellikle istemciler sunucuyla birlikte yükseltilemiyorsa bu sözleşmeleri kendi uyumluluk politikanızla değiştirin.

Her yazarı envantere alın. HTTP işleyicileri tek değişiklik kaynağı değildir. Kuyruk tüketicileri, zamanlanmış görevler, içe aktarma betikleri, veri onarım araçları, veritabanı tetikleyicileri ve doğrudan yönetim işlemleri eski biçimli satırlar üretmeyi sürdürebilir. Uygun olduğunda veritabanı bağlantılarını uygulama adıyla etiketleyin ve gözden kaçan süreçleri görünür kılmak için geçiş yollarının kullanımını kaydedin.

Uzun ömürlü süreçler prepared statement'lar, önbelleğe alınan meta veriler veya nesne ilişkisel eşleme katmanı nedeniyle eski varsayımları koruyabilir. Contract öncesinde kademeli yeniden başlatmaları ve bağlantı havuzu davranışını test edin. Yakın zamanda trafik göndermemiş bir süreç, nadir bir görev ilk çalıştığında yine de hata verebilir.

Veritabanını zorlamadan veri backfill edin

PostgreSQL ile hızla prototip oluşturun
Postgres destekli bir uygulama kurun ve yayınlarken şemanızı güvenle geliştirin.

Güvenli bir backfill küçük, devam ettirilebilir grupları günceller ve üretim sağlığı kötüleştiğinde yavaşlar. Yalnızca canlı yazıcılar yeni gösterimi sürdürebildikten sonra başlar.

Grupları evrensel satır sayısına göre değil, geçen süreye ve veritabanı etkisine göre seçin. Bin dar satır milisaniyelerde bitebilir; büyük değerler veya pahalı dönüşümler içeren bin satır önemli I/O üretebilir. Temkinli başlayın ve saniyeler içinde biten işlemleri hedefleyin. Kilitler ve eski satır sürümleri tek işlemde birikmesin diye gruplar arasında commit edin.

PostgreSQL, düz bir UPDATE üzerinde doğrudan ORDER BY ve LIMIT desteklemez. Bir common table expression ile grup seçin, ardından bu satırları güncelleyin:

WITH batch AS (
    SELECT id
    FROM my_table
    WHERE id > $1
      AND new_col IS NULL
    ORDER BY id
    LIMIT 1000
)
UPDATE my_table AS target
SET new_col = transform_expression(target.old_col)
FROM batch
WHERE target.id = batch.id
  AND target.new_col IS NULL
RETURNING target.id;

Uygulama en büyük tamamlanmış id değerini imleç olarak kaydeder. Koşullu güncelleme, yeniden çalıştırmaları idempotent yapar; commit sonrasında oluşan çökme daha önce işlenen satırları bozmaz. İmlecin commit edilmemiş grubun ötesine geçemeyeceği kadar dikkatle ilerleme saklayın.

Artan id imleci tablonun başını tekrar tekrar taramayı önler; ancak imlecin altında eklenen satırları veya geç yapılan düzeltmeleri yakalayamaz. Tüm kalan NULL değerler üzerinde telafi turuyla bitirin. Tanımlayıcılar sıralı değilse veya satırlar uygunluk durumları arasında geçebiliyorsa, tek ileri taramanın yeterli olduğunu varsaymak yerine iş tablosu ya da açık bir kontrol noktası kullanın.

Birden çok worker, FOR UPDATE SKIP LOCKED ile satırları sahiplenebilir; ancak paralellik yazma baskısını artırır ve ilerleme takibini karmaşıklaştırır. Atlanan satırları kalıcı olarak geçen bir imleçle paralelliği birleştirmeyin. Sahiplenilen tanımlayıcılardan oluşan kuyruk veya yinelenen uygunluk taraması, paralel worker'lar için daha güvenlidir.

Sorgu gecikmesi, etkin bağlantılar, kilit beklemeleri, WAL üretimi, replika replay gecikmesi ve silinmiş satır artışı gibi üretim ölçümlerine göre yavaşlatın. Eşik aşılırsa duraklatın, ardından kontrol noktasından devam edin. Sabit beklemeler basittir; veritabanından gelen geri bildirim trafik değişimlerine daha iyi yanıt verir.

Yalnızca bazı satırlar işlem gerektiriyorsa her satırı değiştirmeyin. Yeni alana, kaynak durumuna veya taşıma işaretçisine göre filtreleyin. Dönüşüm pahalıysa, tutarlılığın izin verdiği yerde hesaplamayı güncelleme işlemi dışında yapın; sonra kısa koşullu yazma gönderin. Sessizce veri uydurmak yerine reddedilen değerlerin sayısını ve örneğini tutun.

Autovacuum ve replikalar her güncellemeden sonra oluşan işi kaldırmalıdır. Backfill primary üzerinde başarıyla tamamlanırken replikalar çok geride kalabilir veya tablo şişmesi sonraki sorguları bozabilir. Hız sınırları yalnızca grubun anlık çalışma süresini değil, bu gecikmeli maliyeti de hesaba katmalıdır.

Veriyi ve üretim trafiğini doğrulayın

Bir taşıma, ancak veri kontrolleri, uygulama telemetrisi ve bağımlılık kanıtları yeni yolun yetkili olduğunu birlikte gösterdiğinde contract için hazırdır. Tamamlanan görev sayacı tek başına doğruluğu kanıtlamaz.

Önce tamlık ve tutarlılığı inceleyin. PostgreSQL'nin IS DISTINCT FROM ifadesi, taraflardan biri NULL olduğunda bilinmeyen sonuç üreten <> ifadesinden farklı olarak NULL değerlerini açıkça ele alarak karşılaştırır:

SELECT count(*)
FROM customers
WHERE normalize_phone(phone) IS DISTINCT FROM phone_e164;

Yoğun çalışan, çok büyük tabloda dizinsiz tam tablo sayımını tekrar tekrar yapmayın. Bir kez kontrollü doğrulama, sınırlı tanımlayıcı aralıkları, örneklem veya tabloda ilerleyen geçici bir doğrulama süreci kullanın. Doğru yöntem, hatalı olmanın maliyetine ve kullanılabilir veritabanı kapasitesine bağlıdır.

Doğrulama şunları kapsamalıdır:

  • Yeni alanı gerektiren satırlarda beklenmeyen eksik değer kalmaması.
  • Yeni değerin, hatalı ve boş girdiler dahil, üzerinde anlaşılan dönüşümle eşleşmesi.
  • Geçmiş veri turu bittikten sonra yeni satırların ve güncellemelerin tutarlı kalması.
  • Geri dönüş okuma kullanımının planlanan eşiğe ulaşması, sunucu tarafından denetlenen trafikte genellikle sıfır olması.
  • Hata oranlarının, sorgu gecikmesinin, kilitlerin ve replika gecikmesinin sürüm sınırları içinde kalması.

Sütunların yanında iş sonuçlarını da karşılaştırın. Taşıma fiyatları, izinleri, hesap durumunu veya tanımlayıcıları değiştiriyorsa kullanıcıların bağlı olduğu toplamları ve değişmez kuralları doğrulayın. İki sütun mekanik olarak eşleşirken ikisi de yanlış iş kuralını kodlayabilir.

Temizlikten önce tam bir çalışma döngüsünü gözlemleyin. Doğru süre sabit bir haftalık kurala değil, sistemin gerçek davranışına dayanır. Ay sonu işlemleri, seyrek çalışan faturalama görevi, gecikmiş kuyruk tekrar denemeleri veya eski bir mobil istemcinin azami ömrü dahil edilmelidir. Her tüketicinin taşındığına dair kanıtı kaydedin.

Uygulama mimarisi izin veriyorsa okuma geçişini canary olarak uygulayın. Trafiğin küçük bir bölümünü yeni okuma yoluna gönderin, sonuçları karşılaştırın ve kademeli olarak genişletin. Geri dönüş eylemini basit tutun: backfill'i tersine çevirmeden okumaları yerleşik gösterime yönlendirin.

Veri hazır olduktan sonra kısıt ekleyin

Kısıtlar, ancak tüm yazıcılar kurala uyduğunda ve mevcut veri doğrulandığında sıkılaşmalıdır. Expand aşamasında NOT NULL, check veya foreign key uygulamak trafiği engelleyebilir ya da eski bir sürecin yazmalarını reddedebilir.

PostgreSQL, check kısıtını NOT VALID olarak ekleyebilir. Bu, geçmiş satırların tamamını hemen taramadan yeni veya değişen satırlarda kuralı uygular. Backfill sonrasında ayrı doğrulayın:

ALTER TABLE customers
ADD CONSTRAINT customers_phone_e164_present
CHECK (phone_e164 IS NOT NULL) NOT VALID;

ALTER TABLE customers
VALIDATE CONSTRAINT customers_phone_e164_present;

Doğrulama başarıyla tamamlandığında, desteklenen PostgreSQL sürümleri sütunu NOT NULL yaparken bu kanıtı kullanabilir ve başka bir tam tablo taramasını önleyebilir. Son değişiklik yine güçlü tablo kilidi ister; bu nedenle sınırlı kilit zaman aşımı ve yeniden deneme planı kullanın:

ALTER TABLE customers
ALTER COLUMN phone_e164 SET NOT NULL;

ALTER TABLE customers
DROP CONSTRAINT customers_phone_e164_present;

Geçici check faydalıysa kalabilir; ancak eşdeğer kısıtları tutmak kuralı değiştirmeden katalog karmaşası ekler.

Foreign key'ler de NOT VALID ve VALIDATE CONSTRAINT ile benzer sırayı izleyebilir. Kısıt oluşturulduktan sonra yeni yazmalar denetlenir, geçmiş doğrulama ise daha sonra yapılır. Başvurulan ilişkide silme veya güncelleme davranışı aksi halde pahalı taramalara yol açacaksa destekleyici dizini bilinçli biçimde ekleyin.

Uygulama doğrulaması veritabanı zorlamasından önce gelmelidir, ancak onun yerini tutmaz. Kod daha anlaşılır kullanıcı hataları üretir; veritabanı ise her yoldan yazılan veriyi korur. Dağıtım sırasında, bağımlılık incelemesinin kaçırdığı yazıcıyı bulmak için kısıt ihlallerini izleyin.

Eski yolu güvenle contract edin

Yayın dostu dağıtımları deneyin
Sonraki sürümünüzü net bir expand aşaması ve kolay geri dönüş yoluyla yayınlayın.

Contract aşaması, veritabanı nesnelerini kaldırmadan önce uygulama bağımlılıklarını kaldırmalıdır. Telemetri ve doğrulama yeni yolun yetkili olduğunu gösterdiğinde temizlik ayrı sürümler halinde ilerleyebilir.

Önce eski alanı okumayı bırakın ve geri dönüş mantığını kaldırın. Ardından onun yazmalarını devre dışı bırakın ve nadir yolları yakalayacak kadar üretimi gözlemleyin. Eski gösterimden söz eden feature flag'leri, tetikleyicileri, uyumluluk görünümlerini, onarım betiklerini ve zamanlanmış görevleri kaldırın. Dışa aktarılan kaynakta ve taşıma kodunda arama yapın; ana depo dışındaki raporları, entegrasyon sorgularını ve change-data-capture yapılandırmalarını da inceleyin.

Güvenli temizlik sırası şöyledir:

  • Geri dönüş okumalarını kaldırın ve telemetride görünmediklerini doğrulayın.
  • Eski yazmaları durdurun ve senkronizasyon kodunu silin.
  • Tüm dağıtılabilir sürümlerde uygulama başvurularını kaldırın.
  • Uygun çevrimiçi yöntemle eski dizinleri ve kısıtları kaldırın.
  • Eski sütunu veya tabloyu sonraki veritabanı sürümünde silin.

PostgreSQL'de sütun silme esas olarak katalog değişikliğidir, ancak yine de ACCESS EXCLUSIVE kilidi ister. Bu nedenle kısa bir ifade uzun işlemin arkasında bekleyebilir ve sonraki işleri engelleyebilir. Kilit zaman aşımı uygulayın, uzun işlemleri önceden inceleyin ve denemeyi daha düşük riskli döneme planlayın.

Yazmaları engellemek kabul edilemezse eski bir dizin için DROP INDEX CONCURRENTLY kullanın. Eşzamanlı oluşturmada olduğu gibi işlem bloğunda çalışamaz ve taşıma aracının ele alması gereken kısıtları vardır.

Kod temizliğini ve fiziksel silmeyi tek sürümde birleştirmeyin. Ayrım, temizlenmiş uygulamanın kullanılmayan nesneyi hâlâ içeren veritabanıyla çalışmasını sağlar. Uygulama sorunu çıkarsa, şemayı yeniden oluşturmadan veya veriyi yeniden kurmadan geri dönüş mümkün kalır.

Bir tabloyu silmeden önce sequence, view, function, yetkiler, tetikleyiciler, replication publication'ları ve dış sorguların sahipliğini kontrol edin. Üretim taşımasında CASCADE komutunu kısayol olarak kullanmayın; amaçlanan değişikliğin parçası olmayan bağımlılıkları kaldırabilir.

Geri dönüşü ve başarısız adımları yönetin

Geri dönüş planı, tek bir genel down migration'a güvenmek yerine her aşama için güvenli eylemi tanımlamalıdır. Ekleyici nesnelerin, veri taşımanın, okuma geçişlerinin ve silmenin kurtarma özellikleri farklıdır.

Expand kilit alamazsa uygulamayı değiştirmeyin ve engelleyen işlemi çözdükten sonra yeniden deneyin. Eşzamanlı dizin oluşturma başarısız olursa geçersiz dizin bırakıp bırakmadığını inceleyin ve yeni denemeden önce o nesneyi temizleyin.

Backfill yük oluşturursa duraklatın. Commit edilmiş idempotent gruplar yerinde kalabilir. Grup boyutunu veya hızı düşürün, pahalı dönüşümü düzeltin ve kontrol noktasından devam edin. Milyonlarca doğru güncellemeyi geri çevirmek, üretimin toparlanmasına yardımcı olmadan riski artırır.

Yeni okuma yolu yanlış sonuç verirse yeni veriyi inceleme için korurken okumaları eski gösterime yönlendirin. Çift yazmayı yalnızca doğru olduğu biliniyorsa sürdürün. Yazıcı hatalıysa etkilenen satırları onarmadan önce onu devre dışı bırakın veya uygulamayı geri alın.

Contract sonrasında kurtarma, eski sürümü dağıtmaktan çok veriyi geri yüklemeyi gerektirebilir. Geri dönüşsüz noktayı açıkça tanımlayın. Sistemin kurtarma politikasının gerektirdiği yedeği veya anlık görüntüyü alın, sürümden önce geri yüklemeyi test edin ve depolama maliyeti uygunsa eski nesneyi üzerinde anlaşılan saklama süresi boyunca koruyun.

Şema komutları işlemsel olabilir, ancak dış etkiler her zaman aynı kapsama girmez. Eşzamanlı dizin işlemleri, kuyruk mesajları, önbellek değişiklikleri ve uygulama dağıtımları tek atomik işlemi paylaşmaz. Çalışma kılavuzu, her kısmi hatadan sonra gözlenebilir durumu ve buradan güvenle devam eden komutu açıklamalıdır.

Yaygın taşıma tuzaklarından kaçının

Başarısız kesintisiz taşımaların çoğu yeni durumu çok erken zorlar veya eski durumun bir tüketicisini unutur. Onaydan önce şu tuzakları açıkça inceleyin:

  • Eski uygulama örneği alanı hâlâ boş bırakabiliyorken NOT NULL eklemek.
  • Büyük backfill işlemini tek işlemde çalıştırmak, kilitleri ve satır sürümlerini çok uzun tutmak.
  • Eski kod özgün adı kullanmaya devam ederken sütun yeniden adlandırmayı ekleyici sanmak.
  • Tüm yazma yolları ve geçmiş satırlar yeni gösterimi doldurmadan okumaları değiştirmek.
  • Başarılı dağıtımı raporların, worker'ların, replikaların ve entegrasyonların uyumlu olduğuna dair kanıt saymak.

Bir başka ince hata çift yönlü senkronizasyondur. Tetikleyici old_col değerini new_col alanına kopyalarken uygulama kodu new_col değerini tekrar old_col alanına kopyalar. Normalleştirme veya tetikleyici sırası farkları döngü yaratabilir, kasıtlı değerlerin üzerine yazabilir ya da sahipliği belirsizleştirebilir. Tek yönü tercih edin ve her sürümde hangi gösterimin yetkili olduğunu belgelendirin.

Varsayılanlar, eksik yazıcı güncellemelerini gizleyebilir. Yeni zorunlu sütun boş veya genel varsayılan alırsa eski kod uyumlu görünürken anlamsal olarak geçersiz veri saklar. Yokluğun yararlı tanı bilgisi taşıdığı durumda nullable geçiş kullanın; ardından her yazıcı anlamlı değer sağladığında gerçek kuralı uygulayın.

Feature flag tek başına uyumsuz şema komutunu güvenli kılmaz. Devre dışı kod yolu eski süreç tarafından hâlâ yüklenmiş, hazırlanmış veya çalıştırılmış olabilir. Hiçbir dağıtılabilir ya da etkin sürüm başvurmadan veritabanı nesnesi kaldırılmamalıdır.

Taşıma sahipliği de önemlidir. Doğrulama ve kaldırma tarihleri dahil, geçişten contract aşamasına kadar bir kişi veya ekip sorumlu olsun. Aksi halde geçici sütunlar, bayraklar ve senkronizasyon görevleri aylarca kalabilir; sonraki her değişikliğin maliyetini artırır.

Telefon sütununu kesinti olmadan değiştirin

Taşımalarda Planning Mode'u kullanın
Koder.ai Planning Mode ile sürümleri, backfill işlemlerini ve doğrulama sorgularını planlayın.

customers.phone alanını normalleştirilmiş customers.phone_e164 ile değiştirmek için ekleyici sütun, tanımlı dönüşüm politikası, uyumlu kod, sınırlı backfill, okuma geçişi ve gecikmeli temizlik gerekir. Saklanan her değer otomatik normalleştirilemeyeceği için dönüşüm politikası SQL'den önce gelmelidir.

Mevcut değerleri sınıflandırarak başlayın. Gerekli ülke bilgisi biliniyorsa geçerli numaralar dönüştürülebilir. Boş değerler NULL olabilir. Belirsiz veya bozuk numaralar tahmin edilmek yerine istisna raporuna girmelidir. Ürünün her müşterinin telefon numarasını zorunlu tutup tutmadığına karar verin; bu, daha sonra NOT NULL kullanımının uygun olup olmadığını belirler.

Sütunu kısa kilit zaman aşımıyla ekleyin:

BEGIN;
SET LOCAL lock_timeout = '2s';

ALTER TABLE customers
ADD COLUMN phone_e164 text;

COMMIT;

Yeni girdiyi normalleştiren ve phone ile phone_e164 alanlarını tek işlemde yazan kodu dağıtın. Başlangıçta okumaları phone üzerinde tutun. Müşteri fixture'ları oluşturan hesap içe aktarımları, destek araçları, worker görevleri ve testler dahil her yazıcıyı güncelleyin.

Uygun satırları kısa işlemlerde backfill edin. Son işlenen tanımlayıcıyı, dönüştürülen ve atlanan sayılarını, her hata kategorisinin nedenini kaydedin. Görevi üretim gecikmesine ve replika gecikmesine göre hız sınırlayın. İleri tur bittiğinde eşzamanlı eklemeleri veya yeniden başlatma sonrası kaçan satırları yakalamak için uygun NULL değerleri yeniden tarayın.

Uygulamayla aynı normalleştirme kurallarıyla tutarlılık kontrolleri çalıştırın; ardından uluslararası önekleri, dahili numaraları, boşları, yinelenen iletişim kayıtlarını ve eski içe aktarılan veriyi elle örnekleyin. Satır sayısı kapsama alanını kanıtlar, telefon numarasının doğruluğunu değil.

Mevcutsa phone_e164 döndüren, phone değerini yalnızca kaydedilmiş istisna için kullanan okuma yolunu dağıtın. Geri dönüş kullanımını ve normalleştirme hatalarını izleyin. Geri dönüşü kalıcı davranış haline getirmek yerine kalan istisnaları çözün.

Yeni alan yetkili olduğunda geri dönüşü kaldırın ve phone yazmayı durdurun. Uygun bir çalışma döngüsü boyunca nadir görevleri ve entegrasyon trafiğini gözlemleyin. Doğrulanmış kısıtı yalnızca ürün kuralı gerektiriyorsa ekleyin.

Son olarak phone alanına ait kod başvurularını kaldırın. Dizinlerini veya kısıtlarını ayrı kaldırın, ardından sütunu sınırlı kilit beklemeli sonraki taşımada silin. Okuma geçişi bu silme öncesinde herhangi bir noktada başarısız olursa iki sütun da kullanılabilirken uygulama davranışını geri alın.

Bu örnek, şema mekaniğinin çözemeyeceği bir alan sorununu da gösterir: İnsanların girdiği veriyi bölmek veya normalleştirmek her zaman kayıpsız değildir. Taşıma planı istisnaları korumalı ve bunları çözebilecek bir sorumluya yol vermelidir.

Her sürümü yayınlamadan önce kontrol edin

Sürüm kontrol listesi uyumluluğu kanıtlamalı, üretim etkisini sınırlamalı ve mevcut aşamanın kurtarma eylemini belirtmelidir. Operatörün olay sırasında amacı yeniden kurmaması için kanıtı değişiklikle birlikte saklayın.

Dağıtımdan önce şunları doğrulayın:

  • Uygulama sürümü, bu sürümden önceki ve sonraki veritabanı durumuyla çalışıyor.
  • Trafik arkasında bekleyebilecek şema komutları için kilit ve ifade zaman aşımları ayarlı.
  • Backfill veya doğrulama görevi ilerleme, duraklatma, sürdürme ve hız sınırlama denetimlerine sahip.
  • Panolar hataları, gecikmeyi, kilitleri, veritabanı yükünü, WAL'i ve replika gecikmesini kapsıyor.
  • Geri dönüş eylemi, zaten kaldırılmış nesneye bağlı olmadan test edilmiş.

Açık tamamlama koşulları kaydedin. Örnekler, tam bir görev döngüsünde sıfır yeni tutarlılık hatası, sunucu denetimli trafikte sıfır geri dönüş okuması, bilinen her tüketicinin yükseltilmesi ve başarılı kontrollü doğrulama sorgusudur. İşlenen yüzde, backfill sırasında yararlıdır; ancak yüzde 100 işlenmiş olmak yüzde 100 doğru olmakla aynı şey değildir.

Taşıma sıralamasını kod incelemesinden bağımsız olarak gözden geçirin. Doğru SQL ve uygulama değişiklikleri koleksiyonu bile dağıtım onları yanlış sırada çalıştırırsa başarısız olabilir. Bir adımın ancak diğer adım tamamlandıktan sonra başlayabileceğini belirtin.

Mümkün olduğunda durdurma koşulları sayısal olmalıdır. Kabul edilebilir sorgu gecikmesini, kilit beklemesini, replika gecikmesini, hata oranını ve grup süresini tanımlayın. Eşik aşıldığında operatör, olay sırasında yeni onay aramadan görevi duraklatması, bekleyen ifadeyi iptal etmesi veya okumaları yönlendirmesi gerekip gerekmediğini bilmelidir.

Taşıma; yeni gösterim okuma ve yazmaları ele aldığında, geçmiş veri doğrulamadan geçtiğinde, eski nesne kaldırıldığında ve geçici operasyonel düzenek ortadan kalktığında tamamlanır.

Süreci tekrarlanabilir hale getirin

Tekrar kullanılabilir taşıma çalışma kılavuzu, expand/contract yaklaşımını adı belli sorumlular ve ölçülebilir geçitlerle sıradan sürüm işine dönüştürür. Canlı dağıtımda izlenecek kadar kısa, kısmi hata durumlarını açıklayacak kadar ayrıntılı olmalıdır.

Çalışma kılavuzunda beş bölüm kullanın:

  • Expand: Tam şema işlemleri, beklenen kilitler, zaman aşımları ve işlem gereksinimleri.
  • Uyumluluk: Etkilenen kod, yazıcılar, okuyucular, bayraklar, istemciler ve dağıtım sırası.
  • Backfill: Dönüşüm politikası, gruplama, kontrol noktaları, yavaşlatma ve istisna yönetimi.
  • Doğrulama: SQL kontrolleri, iş değişmezleri, telemetri ve tamamlama eşikleri.
  • Contract: Bağımlılıkların kaldırılması, gözlem süresi, fiziksel temizlik ve kurtarma sınırları.

Her geçiş nesnesine bir sorumlu ve beklenen bitiş tarihi atayın. Sütunları, dizinleri, bayrakları, tetikleyicileri ve görevleri aynı yerde takip edin. Temizlik isteğe bağlı bakım değildir; taşımanın parçasıdır.

Koder.ai ile çalışan ekipler, üretim değişiklikleri başlamadan önce bu aşamaları ve kontrol noktalarını ayrıntılandırmak için Planning Mode'u kullanabilir. Kaynak kod dışa aktarma özelliği, taşıma SQL'i ve uyumluluk mantığının diğer uygulama kodlarıyla aynı incelemeden geçmesini sağlar. Koder.ai dağıtım, barındırma, anlık görüntüler ve geri dönüş sunar; ancak uygulama geri dönüşünün commit edilmiş veri dönüşümünü tersine çevireceği varsayılmamalıdır. Veritabanı kurtarma planı eski gösterime artık ihtiyaç duymayana kadar şema uyumluluğunu koruyun.

Mümkünse yoğun yazma işlemlerini düşük trafikli zamanlara planlayın, ancak zamanlamayı tek güvenlik denetimi saymayın. Sınırlı işlemler, geri bildirim temelli yavaşlatma, gözlenebilir ilerleme ve test edilmiş duraklatma eylemi; trafik veya veri beklenmedik davrandığında çevrimiçi taşımayı yönetilebilir kılar.

SSS

Şema değişikliği neden kesintiye yol açabilir?

Şema değişiklikleri, eski ve yeni uygulama sürümleri farklı veritabanı yapıları beklediğinde üretimi bozabilir. Kademeli dağıtım sırasında iki sürüm aynı anda çalışabilir; bu yüzden bir sütunu erken kaldırmak veya yeniden adlandırmak okuma ya da yazma hatalarına yol açar.

Expand/contract taşıma deseni nedir?

Expand/contract, uyumsuz bir değişikliği güvenli aşamalara böler. Önce yeni yapıyı eklersiniz, sonra kodu ve veriyi ona taşırsınız, en son da tüm tüketiciler eski yapıyı bırakınca onu kaldırırsınız.

Bir veritabanı sütununu kesinti olmadan nasıl yeniden adlandırır veya değiştiririm?

Önce yeni sütunu ekleyin ve eskisini yerinde bırakın. İki alanla da çalışabilen kodu yayınlayın, mevcut satırları küçük gruplarla backfill edin, doğrulamanın ardından okumaları değiştirin ve eski sütunu sonraki bir sürümde kaldırın.

PostgreSQL'de trafiği engellemeden sütun ekleyebilir miyim?

Çoğu durumda evet. Varsayılanı olmayan nullable bir sütun PostgreSQL'de genellikle kısa süren bir meta veri değişikliğidir, ancak yine de tablo kilidi ister. Kısa bir kilit zaman aşımı ayarlayın; böylece taşıma uzun bir işlemi beklemek yerine başarısız olur.

Yazmaları engellemeden dizin nasıl oluşturulur?

Tablonun yazılabilir kalması gerekiyorsa CREATE INDEX CONCURRENTLY kullanın. İşlem daha uzun sürer, veritabanına yük getirir ve işlem bloğunda çalışamaz. Çalışırken gecikmeyi, WAL'i ve replika gecikmesini izleyin.

Uygulama eski ve yeni alanlara ne zaman çift yazmalıdır?

İki gösterimin de güncel kalması gerektiğinde, iki değeri mümkünse aynı veritabanı işlemi içinde yazın. Alanlar çelişirse hangisinin öncelikli olduğunu belirleyin; API'lerde, worker'larda, içe aktarımlarda ve destek araçlarında aynı normalleştirme kurallarını kullanın.

Büyük bir PostgreSQL tablosunu güvenle nasıl backfill ederim?

Kısa, devam ettirilebilir gruplar işleyin ve her grubun ardından commit edin. Bir kontrol noktası saklayın, yalnızca hâlâ işlem gerektiren satırları güncelleyin; sorgu gecikmesi, kilit beklemeleri, WAL hacmi veya replika gecikmesi yükseldiğinde işi yavaşlatın ya da duraklatın.

Bir backfill işleminin tamamlandığını ve doğru olduğunu nasıl anlarım?

Backfill bitti diye okumaları değiştirmeyin. Gerekli değerlerin bulunduğunu kontrol edin, eski ve yeni gösterimleri karşılaştırın, geri dönüş okumalarını izleyin ve geçmiş veri geçişinden sonra yeni yazmaların tutarlı kaldığını doğrulayın.

NOT NULL, check kısıtları veya foreign key'leri ne zaman eklemeliyim?

Sıkı kısıtları, mevcut veri doğrulamadan geçtikten ve tüm etkin yazıcılar geçerli değerler gönderdikten sonra ekleyin. PostgreSQL bazı kısıtları NOT VALID ile eklemenize, yeni satırlarda uygulamanıza ve geçmiş satırları ayrı doğrulamanıza izin verir.

Eski şema yolunu kaldırmak ne zaman güvenlidir?

Önce geri dönüş okumalarını kaldırın, ardından eski yazmaları durdurun ve sistemi tam bir çalışma döngüsü boyunca gözlemleyin. Tüm uygulamalar, görevler, raporlar, entegrasyonlar ve istemciler eski nesneye başvurmayı bıraktıktan sonra ilgili kodu kaldırın; veritabanı sütununu veya tablosunu daha sonraki bir sürümde silin.

Related posts