
14 yıllık mühendislik deneyimimde, birçok insanın yepyeni bir hizmet üzerinde çalışma fırsatına dayanarak kariyer kararları aldığını gördüm. Bu kararda yanlış bir şey yok. Ancak bugün sıkıcı geçiş projeleri üzerinde çalışmanın çelişkili bir örneğini ele alacağız. Kariyerimin başlarında farkına varmadığım şey, temel yazılım geliştirme öğrenimimin çoğunun geçiş projeleri olan projelerden geldiğiydi; örneğin, temel bir veri deposunu başka bir bulut tabanlı teknolojiye geçirmek veya monolitik bir hizmeti yeni mikro hizmetler lehine kullanımdan kaldırmak, vb.
Bunun nedeni, göçlerin doğası gereği zor olmasıdır: Yıllar boyunca birden fazla mühendis tarafından oluşturulmuş ve geliştirilmiş kullanılabilirlik, ölçek, gecikme ve müşteri deneyimi konusunda mevcut bir çıtayı karşılamak, hatta aşmak zorundasınız. Yepyeni bir sistemde bu kısıtlamalarla karşılaşmayacaksınız çünkü bunları tanımlamakta özgürsünüz. Dahası, göçler konusunda ne kadar titiz olursanız olun, sistemin yeni bölümlerine geçtiğinizde uğraşmanız gereken dolapta gizli iskeletler olacaktır (Doordash'in bir veritabanı alanı için Int'ten BigInt'e göçünün engelleyicilerle dolu olduğunu anlatan bu ilginç makaleye göz atın).
Bu projeler sizi test metodolojileri, yeni sistemlerden elde edilen sonuçların doğruluğu, yazılım dağıtım planları, yazılım geri alma planları vb. hakkında titizlikle düşünmeye zorlar, böylece hizmet verdiğiniz mevcut müşterileriniz olmadığı için her zaman yepyeni bir sistem üzerinde çalışma konusunda stres yaşamazsınız. En sıkıcı kısım ise mevcut müşterilerin aslında onların bilgisi olmadan temeldeki bir sistemi veya kod tabanını değiştirdiğinizi bilmemesi gerektiğidir.
Yeni mühendislerin yeni bir teknolojiyi denemek ve mevcut bir işlevi değiştirmek istediklerini veya birinin kod tabanını tamamen yeniden düzenlemek istediğini sık sık görüyorum. Bu, sınırlı bir değişiklikse (örneğin, hizmette küçük bir işlem gerçekleştirmek için iyi test edilmiş bir açık kaynaklı kütüphane kullanmak, vb.), umursamıyorum. Ancak, büyük bir mimari değişiklikse veya tüm bir kod tabanını yeniden çalışıyorsa, ünlü bir mühendislik ilkesini hatırlamak önemlidir: "Öncekine Saygı Gösterin." (Eski koddan efsanevi kod olarak bahseden bu tweet'i komik buldum.)
Göç projelerinin noktasına geri dönersek, aynı sorunu nispeten daha az çabayla çözüp çözemeyeceğinizi veya kod tabanında veya mimaride büyük bir yenileme yapıp yapamayacağınızı değerlendirmek her zaman akıllıca olacaktır. Ancak yeni bir teknoloji veya tasarım deseni kullanmanın cazibesi her zaman caziptir, peki bu kararı nasıl değerlendireceğiz? Göç yolculuğuna çıkmadan önce başlamanıza yardımcı olacak birkaç soru ve husus şunlardır:
Bu sorunu çözmezsek ve ekip büyük bir geçiş projesinin büyük bir taahhüdü olmadan bunu çözmek için tüm seçenekleri tüketmişse, işletme (veya müşteri deneyimi) olumsuz etkilenir mi veya gelecekte etkilenir mi? Ekibinizde olmayan ve muhakemenizi baskı altında test etmek için şeytanın avukatı gibi davranabilen başka bir kıdemli mühendisin incelemesini tercih edin. Bazı gerekçelendirme örnekleri, her özellik lansmanında çevikliği 4 geliştirici ayı iyileştirmek, p99 gecikmesini 400 ms iyileştirmek için farklı hizmetler için farklı teknoloji yığınları kullanmak, X TPS'nin ötesinde ölçekleme darboğazlarını kaldırmak vb. olabilir. Bu tür durumlarda onaylama önyargınızı kırmak için her zaman anlaşmazlıkları arayın.
Göçü gerçekleştirme çabalarını, sağlayacağı faydalarla karşılaştırın, böylece projenin faydalarını toplamaya başlamanın ne kadar süreceğini tahmin edebilirsiniz. Paylaşabileceğim kişisel bir örnek şu şekildedir:
Ekibim, iki farklı müşteri tabanına hizmet eden iki ayrı sisteme sahipti ve her yeni özellik lansmanı, ekibin bu ayrı sistemlerde benzer, ancak birebir aynı olmayan değişiklikler yapmasını gerektiriyordu. Genel olarak, çoğaltma, özellik başına ayda 1 geliştirici ek çabasına yol açtı. Her yıl yaklaşık 4 bu tür özellik başlattık ve bu da 4 geliştirici ayı boyunca çoğaltılmış veya boşa harcanmış çabaya yol açtı. Bu, mühendisler için sinir bozucuydu. Mühendislerden biri, bu iki sistemi birleştirme önerisiyle geldi ve çabanın 24 geliştirici ayı olacağını tahmin etti. Ekibin göçün faydalarını toplamaya başlaması 24 özellik lansmanı ve 6 yıl (yılda 4 özellik başlatıldığını varsayarak) alacaktı. Göçü yapmadık ve çoğaltma çabasını %50 oranında azaltmak için paylaşımlı kütüphaneleri kullanma gibi alternatif bir yaklaşıma geçtik ve daha sonra, 3 yıl sonra sistemi başka bir hizmet lehine kullanımdan kaldırdık.
Bazı durumlarda, geçiş daha geniş bir hedefe ulaşmak için yukarıdan aşağıya bir rehberliktir (örneğin, Amazon'un Oracle'dan ayrılması ) ve bu durumda analizi yapmaya devam edebilirsiniz ancak projeye devam etmek için onay almanız gerekmez.
Göçü yapmak için doğru gerekçeleri belirledikten ve gerekçeleri bazı dış mühendisler veya liderlerle baskı altında test ettikten sonra, bir sonraki adımlara geçme zamanı gelmiş demektir.
Bu, bir sistem tasarım görüşmesine hazırlanırken yapacağınız şeye benzer. İşlevsel ve işlevsel olmayan gereksinimler ortaya konduğunda, mevcut sistemi şimdilik unutmak ve hiçbir kısıtlama olmasaydı yeni bir sistemi nasıl inşa edeceğinizi ortaya koymak akıllıca olacaktır.
Bu egzersizi yapmanın nedeni, mevcut ekip üyelerinin çoğunun mevcut sistemden çok da farklı olmayan yeni bir sistem kurma konusunda bilinçsiz bir önyargıya sahip olması ve bu durumun birçok durumda göçün amacını boşa çıkarmasıdır. Geçmişimden başka bir örneği ele alalım:
Mevcut sistemler üzerinde çalışmayan daha deneyimli birini dahil etmek, daha ölçeklenebilir, gerçek zamanlı ve bakımı daha kolay olan tamamen farklı bir sistem inşa etme konusunu gündeme getirdi. Bu her zaman mümkün olmayabilir, ancak bu egzersizi denemekte zarar yoktur.
Daha önce önerdiğimiz gibi birebir geçiş yapıyorsanız (yani, şirket içi bir SQL DB'yi bulut SQL DB'sine taşıyorsanız), işlevsel olmayan gereksinimleri karşılamanız daha kolay olabilir. Ancak, son sisteminiz mevcut sistemden önemli ölçüde farklıysa, sisteme yerleşik anti-örüntüyü düzeltmek için en azından bir girişimde bulunmalısınız. Örneğin, veritabanındaki bir anahtarda güncelleme değişikliği için yoklama yapmak yerine, abonelere bir Pub/Sub hizmeti kullanarak bir değişiklik bildirimi yayınlayabilirsiniz.
Ancak, dağıtılmış sistemlerdeki her projede olduğu gibi, işlevsel olmayan gereksinimler söz konusu olduğunda geçişlerin de bazı dezavantajları olacaktır ve bunun için plan yapmanız gerekecektir. Örneğin, iki ayrı iş ile ilgili hesaplamayı (teslimat tarihi tahmini ve nakliye ücreti tahmini) işleyen %99,9 kullanılabilirliğe sahip bir monolit hizmet varsa ve bu sorumluluğu her biri %99,9 kullanılabilirliğe sahip iki mikro hizmete (A (Teslimat Tarihi Tahmin Hizmeti) ve B (Nakliye Ücretleri Tahmini) bölmeye karar verirsek, sistemin genel kullanılabilirliği şu şekilde olur:
P(A) * P (B) = 0,999 * 0,999 = %99,8 kullanılabilirlik
Monolitten mikroservisler oluşturmak, kullanılabilirliğin %99,9'dan %99,8'e düşmesine yol açtı.
Unutmayın, istemcinize bir yanıt döndürmek için 'n' servis çağrısından (sıralı veya paralel servis çağrıları) sonuç almanız gerekiyorsa, sistemin nihai kullanılabilirliğine ulaşmak için 'n' servisin her birinin ayrı ayrı kullanılabilirliğini çarpmanız gerekir.
Sistemin orijinal kullanılabilirliğini karşılamak veya aşmak için (yani %99,9), önbelleğe alma, yeniden denemeler vb. gibi diğer teknikleri düşünmemiz gerekecektir. Ancak bu seçeneklerin her birinin kendi dezavantajları vardır. Örneğin, önbelleğe alma, bazı durumlarda, sisteminizin eski verileri tolere edebilmesi gerektiği anlamına gelebilir; yeniden denemeler gecikmelere neden olabilir ve sistemi yeniden deneme fırtınalarına karşı hassas hale getirebilir vb.
Ancak bu egzersizi yapmak, işlevsel olmayan gereksinimler konusunda en azından mevcut bir standardı karşılayıp karşılamadığınızı veya müşterilerinize sağlamak istediğiniz yeni işlevsel olmayan gereksinimler konusunda liderlik onayına ihtiyacınız olup olmadığını görmenizi sağlayacaktır.
Yeni bir sistemle müşterileriniz yeni istemci sürümünüzü benimseyeceklerdir. Göç projelerinde, tüm müşterilerin istemcinin yeni sürümüne geçememesi durumunda ne olacağı sorunuyla uğraşmanız gerekebilir (yani, geriye dönük uyumluluğu düşünmek). Tüm müşterileriniz şirket içindeyse veya şirket dışında sınırlı bir benimsemeniz varsa, tüm müşterilerinizle birlikte çalışarak onları istemcinin yeni sürümüne taşıyabilirsiniz.
Diğer durumlarda, bu kesinlikle mümkün değildir. Örneğin, sektörde yaygın olarak benimsenen büyük bir bulut hizmetine sahipseniz, tüm müşterileri istemcinin yeni bir sürümüne geçmeye zorlamanın bir yolu yoktur. Bu, ekip için önemli engelleyiciler ve bakım yükü ekleyebilir ve bazı durumlarda, çözüm, eski sistemin bakım modunda olduğu iki sistem sürümünü sürdürmektir (yani, bu sisteme yeni müşteri eklenmez) ve müşterilere daha iyi faydalar sağladığı için eski müşterilere sistemin daha yeni bir sürümüne geçmeleri için bir teşvik sağlarsınız.
Ancak, yukarıda paylaştığım bağlantıdaki gibi Doordash'te birincil anahtarın veri türü olarak Int kullanılması durumunda taşma olacağı bir durumla karşılaşırsanız, herkesi göç etmeye zorlamaktan başka seçeneğiniz yoktur.
Yeni sistemler inşa ederken, çoğu mühendis neredeyse tüm kullanım durumlarını kapsamada harika bir iş çıkarır. Ancak, göçlerde bunun tersi olur çünkü sizden önce onlarca, hatta yüzlerce mühendis tarafından geliştirilen, yamalanan ve bakımı yapılan bir sistemi yönetiyorsunuz. Her kullanım durumu, kod yolu veya sistem darboğazı hakkında bilgi edinmek isteseniz bile, tüm hizmeti kavramak zordur.
Bu gibi durumlarda yapılacak en basit şey, kör noktalarınızı kapatmak için hangi süreçleri takip edebileceğiniz konusunda benzer göçler gerçekleştirmiş ekiplerden, kıdemli mühendislerden vb. dersler çıkarmaktır. Birçok şirket daha geniş bir organizasyon düzeyinde tasarım ve göç incelemeleri sürecini takip eder. Yaklaşımınızı ve anlayışınızı sağlamlaştırmak için sürecin kutsal bir parçası olarak anlaşmazlıkları arayın. Göçler, beklenmedik şekillerde tetiklenen mayınlarla doludur.
Göçlerin çoğunluğu genellikle aşağıdaki iki kategoriden birinde veya her ikisinin bir kombinasyonundadır:
Hizmet geçişleri: Mevcut bir hizmeti, mevcut hizmetin bazı bölümlerini ve yeni bir hizmeti kullanarak veya mevcut bir sistemi değiştirmek üzere yeni mikro hizmetler başlatarak yeni bir mimari lehine kullanımdan kaldırma.
Veri deposu geçişleri: Mevcut bir veri deposunu kullanımdan kaldırıp yerine yeni bir veri deposu yerleştirmek veya olay odaklı bir sistemden yararlanmak.
Tam bir geçiş örneği bulamasanız bile, bu kovalar için her zaman daha geniş öğrenimler elde edebilirsiniz. Kişisel deneyimime göre, veri deposu geçişleri en zor olanıydı çünkü eski ve yeni veri depoları arasındaki tutarlılık sorunları nedeniyle etkilenen verilerin doğruluğu konusunda endişeler vardı. Örneğin, bir kullanıcı yayılmadaki gecikmeler nedeniyle yeni bir veri deposundan daha eski bir veri sürümü görebilir.
Mevcut ve yeni sistemleri paralel olarak çalıştırırken yalnızca mevcut sistemden veri sunmak, her iki sistemin sonuçlarını gerçek müşteri istekleriyle karşılaştırmanıza olanak tanır. Bu, yeni sisteminizin doğru çalıştığını karşılaştırmak ve doğrulamak için en yararlı ve güçlü adımdır.
Yıllar önce, yeni bir teknik yığına bir hizmet geçişi üzerinde çalıştım. Eski hizmetimiz müşteri istekleri aldığında, arka uçtaki yeni hizmetimize paralel bir asenkron çağrı yapardık. Mevcut ve yeni hizmet sonuçlarını bir S3 konumuna kaydederdik. Daha sonra, herhangi bir tutarsızlığı bulmak ve yeni hizmetle ilgili herhangi bir sorunu belirlemek için günün sonunda bir AWS Athena sorgusu çalıştırırdık. Bu, bir veri deposuyla ele aldığımız başka bir zorlu geçişe kıyasla hala biraz öngörülebilir bir şeydi.
Eski bir SQL veri deposunu, daha güvenilir ve yeni bir veri kaynağından doldurulmuş yeni bir NoSQL veri deposuna taşıyorduk. Ancak, eski ve yeni veri depoları arasında belirli anahtarların güncellendiği zaman tahmin edilemezdi çünkü bunlar tamamen farklı iki sistemden geliyordu.
Eski ve yeni veri depoları arasındaki verileri karşılaştırmak için birden fazla yaklaşımı başarısızlıkla denedikten sonra, veri anahtarları için sürümler yayınlamak üzere yukarı akış ekiplerimizle çalıştık, böylece her iki sistem arasındaki sürümleri kullanarak belirli bir anahtar için veri doğruluğu karşılaştırması yapabildik. Bu, proje sonrası sürümlere ihtiyacımız olmadığı için atılabilir bir işti, ancak bunu halletmenin başka bir yolu yoktu.
Eski ve yeni sistemin sonuçlarını doğru bir şekilde karşılaştırabildiğiniz 5. Adımı çalıştırdıktan sonra bile, sisteminizi nadiren kullanan birkaç müşteriden belirli bir türde talebe asla ulaşamamanız oldukça olasıdır. Bu geçiş projelerinden bazılarında çalışırken "Ya yeni sistemde her şey ters giderse?" diye düşünerek uykusuz kaldım.
Bununla başa çıkmanın en kolay yolu, alarmlarımız beklenmedik bir şey yakaladığında veya trafiği eski sisteme geri taşımak için manuel olarak tetiklediğimizde yeni sisteme bir kapatma düğmesi eklemekti. Dikkat edin, bu kulağa geldiği kadar kolay değil. Bazı durumlarda, eski bir sisteme geçmenin bir yolu olmayabilir ancak bu kaldıraca sahip olmak ekip üzerindeki baskıyı büyük ölçüde azaltacaktır.
Bunun mümkün olmadığı durumlarda, güvenebileceğiniz tek nokta 5. adımda (Eski ve yeni sistemleri paralel olarak çalıştırmak) titiz olmaktır. Bunu, yeni sistemin yavaş ve kademeli bir şekilde kullanıma sunulması izler. Trafiğin küçük bir yüzdesini (%1'i %5, %10, %25, %50, %100 takip eder) yeni bir hizmet tarafından hizmet verilecek şekilde taşıma veya geçiş sırasında yakından çalıştığınız yeni hizmet tarafından hizmet verilecek birkaç müşteriyi elle seçme gibi teknikler kullanarak yavaş ve kademeli bir kullanıma sunma tanımlayabilirsiniz.
Ayrıca, işler ters giderse operatörler tarafından takip edilecek bir olay yanıtlama çalışma kitabını genel olarak incelemek de önemlidir. Her şey başarısız olursa, manuel müdahale gözden kaçan uç durumlara yardımcı olabilir, ancak etkilenen müşteri sayısı binlere çıkarsa bu durum hızla yönetilemez hale gelebilir. Bu, 5 ve 6. maddelerde açıklanan aşamalara yeterli zaman ayırmanın nedenidir.
Göçler üzerinde çalışmak bu becerilerin bazılarını geliştirmenin tek yolu olmasa da, gelecekteki projelerinize uygulayabileceğiniz öğrenimlerinizi kesinlikle hızlandırabilir, bu yepyeni girişimler olsa bile. Göç projeleri daha az gösterişlidir ancak özellikle tasarım belgeleri veya diğer teknik belgeler hakkında geri bildirim sağladığımda beni savaşta test eden projelerdi.
Yani, eğer bunlardan birinde çalışma fırsatı bulursanız, deneyin: hayal kırıklığına uğramayacaksınız ve umarım başkalarına aktararak dayanıklı sistemler inşa edeceğiniz kariyer boyu sürecek bir öğrenme deneyimi yaşayacaksınız.