İşlem Yoğun Girift Sistemlerde Mikroservisler ve İşlem Bütünlüğü

Süleyman Fazıl Yeşil
16 min readOct 26, 2020
Kaynak: http://turnoff.us/geek/the-depressed-developer-37/ Çeviri: Tüm yapman gereken, küçücük projene beş mikroservisle başlamandır.

“Programcılar her şeyin faydasını bilirler, ancak hiçbir şeyin getirisini götürüsünü bilmezler” Rich Hickey

Çoğu iş ilanı analitik düşünen birini arar. Lakin içi boşalmış gibidir kavramın, kulağa afili bir kelimeden ibaretmiş gibi gelir. Kelimeye anlamını teslim edersek, meseleleri analiz edip, getiri ve götürü terazisinde tartarak karar vermek demektir.

Pazara mı gitsem, markete mi? İşe servisle mi gitsem arabayla mı? İşe yakın bir semtte mi ev tutsam, yaşamak istediğim fakat işe uzak olan bir semtte mi? Hayata dair her meselede bir tartma söz konusu. Bir gün içerisinde bunlara benzer yüzlerce karar alıyoruz. Bazılarında sahip olduğumuz bilgi zemininde, bilinçli bir şekilde, etraflıca fayda ve zararını tartarak karar veriyoruz; bazılarınıysa pek üstüne düşmeden otomatik sistemimize havale ediyoruz, dikkatimizi uyaran özel bir unsur yoksa. O da o an baskın gelen bir öğrenmişliğe dayanarak bir tercihte bulunuyor.

Teknoloji alanında hiç bir konuda evrensel doğru yoktur, her şey görecelidir. Doğrular ve cevaplar bağlama göre değişir. Kurumdan kuruma, zamandan zamana, problemden probleme, şartlardan şartlara, ölçekten ölçeğe değişir. Kağıt üzerinde belirli ilkeleriniz olsa da, hayatın değişken koşullarının zorunlu kıldığı bir pragmatiklikle yaşarsınız. Seçiminizin getirisini ve götürüsünü, etki alanının genişliğini ve derinliğini, hayatiyetini tartarak karar almanız gerekir. Yapacağınız seçimin bir etkisi yoksa, vereceğiniz kararın da bir önemi yoktur.

Test yazsam mı, ne kadar yazsam, nereden bakarak yazsam? Bu sorunun bile tek bir doğru cevabı yoktur. Bir pilot çalışma (POC) yapıyorsam muhtemelen sistemin uçtan uca çalıştığını gösterecek geniş kapsamlı bir kaç test ile yetinebilirim. Devreye alınması kesin olan, hayatına ve geliştirilmeye devam edecek olan bir şeyse daha kapsamlı testler yazmaya çalışırım ki ileride hem düzenleme yapmak kolay olur, hem de değişikliklerin sistemi bozmadığından emin olabilirim.

Diğer taraftan hızlıca yüzlerce yazılımcının geliştirdiği bir masaüstü uygulamanızı web tabanlı bir uygulamaya dönüştürmeye çalışıyorsanız, yazılımcılarınız test yazma kültürüne sahip değilse, alışmaları zaman alacaksa, web teknolojisini yeni öğreniyorlarsa, test yazmak çok kolay olmayıp zaman alıyorsa, çok fazla senaryo varsa, yazacağınız birim testler yeterince iyi kalitede olamayacak ve bir yasak savmadan öte bir işlevi olmayacaksa, insanlar şikayet edip duracaklarsa, yeterince de zamanınız yoksa birim test yazmayı zorunlu tutmama kararı alabilirsiniz. Hem zaman kısıtı, hem insan faktörü, hem de birim testlerin getirisi götürüsü sebebiyle birim test yazmak yerine daha kolay ve hızlı bir şekilde yazılabilen, testçilere hatta iş analistlerine yazdırabileceğiniz buna karşın yalnızca önemli bir kaç senaryoyu kapsayan kullanıcı kabul testleriyle, fonksiyonel testlerle ilerleme kararı alabilirsiniz.

Teknik insanlar genellikle teknik kısma odaklanmışlıktan sıyrılıp olayı geniş boyutta, kurumsal ölçekte getirisi ve götürüsü çerçevesinde ele almazlar. Yeni bir araç, teknik, yaklaşım duyduklarında hemen büyülenip büyük bir heyecana kapılırlar. Onu hemen almak, uygulamak, kullanmak isterler. Yeni bir iPhone modeli çıktığında annesinden ısrarla almasını isteyen çocuk gibi. Sınıf arkadaşı almıştır, onun neyi eksik, o da ister, geri kalmak istemez. Bu senaryoda teknik insanlar çocuk rolündedir, vakit ve nakit ayarlaması yapmaya çalışan yönetici, üst yönetici veya patron da aile ekonomisi yapmaya çalışan anne-baba rolündedir.

Abi Kubernetes konteynır yönetim sistemi çok iyi, açık kaynak, arkasında Google var, herkes ona geçiyor bizim de bir an evvel geçmemiz lazım. Amazon ve Netflix mikroservis mimarisini kullanıyorlar, binlerce servisleri varmış biz de geçelim. Blokzincir her şeyi dönüştürecek hemen alıp kullanalım. Kotlin dili çıkmış, uygulama geliştirmeyi kolaylaştırıyormuş, mobil uygulamayı Java’dan Kotlin’e geçirelim. Flutter diye bir şey var, cross-platform, Android/IOS vs uğraşmaya gerek kalmıyor, biz de Flutter’a geçelim. Vue.js süper hızlıymış, e-ticaret siteleri ona geçmeye başlamışlar, biz de ön yüzü Vue.js’e geçirelim, ön yüz uçsun.

Üç beş yazılımcın ve üç beş satır kodun varsa gönlünce dilediğin gibi takıl. Her gün uygulamanı farklı bir dille, teknolojiyle, mimariyle yeniden yaz. Bir gün bir cebinden al ötekine koy, ertesi gün oradan al, berikine koy. Ne kaybedersin ki senin ölçeğinde? Ertesi gün komple değiştirme imkanın olur. Bu arada canının çektiği şeyleri tatmış olursun. Bir şey kazanma peşinde değilsindir, gönlünce yüreğinin götürdüğü yerlere gidip durursun.

Diğer yandan yüzlerce kişinin ürettiği bir sistemle ilgili karar alıyorsak, keyfe keder ilerleyemeyiz. Çünkü vereceğimiz kararlar üç beş kişiyi değil yüzlerce kişiyi etkileyecektir. Yani kuvvet çarpanı çok büyük. Bu nedenle de vereceğimiz karar, kullanacağımız teknoloji, geçmeyi planladığımız mimari, uygulamaya koyacağımız standart bize ne kazandırır ne kaybettirir diye etraflıca düşünmek zorunda kalırız. Çünkü bir şey kazanıyorsak muhakkak başka bir şeyi kaybediyoruzdur. Önemli olan ne kaybettiğimizi sormak, anlamak ve bu kaybın bizim için önemli olup olmadığını değerlendirmektir.

Bu sebeple etki alanı geniş bir meselede verilen kararlar işin sadece teknik boyutuna yaslanamaz. Örneğin yeni bir mimariye geçmeyi tasarlarken, bu mimari ne getirir ne götürür diye düşünmemiz gerekir. Bir tarafa kazançlarımızı koymaya çalışırız, diğer tarafa kayıplarımızı. Performans kazancı ve ölçeklenebilirlik, geliştirme ve bakım maliyetleri, geliştirme hızı, sistem karmaşıklığı ve anlaşılırlığı, bakım kolaylığı ve zorluğu, kırılganlığı ve dayanıklılığı, kurumsal bir uygulamada kullanım için teknik olgunluğu, üretkenliğe etkisi, insanların yaklaşımı ve benimsenme durumu, kültürel değişim ve eski ile yeninin ilişkisi, BT altyapısının değişmesinin işe ne gibi kazanç sağlayacağı gibi şeyleri göz önüne almamız gerekir.

Çünkü bugün biz bu soruları sormazsak, yarın muhakkak başkaları soracaktır. Su akar yatağını bulur derler. İnsanlar kolayı sever, kestirmeyi sever, alışkanlıklarını değiştirmeyi sevmez. Eğer tepede kayda değer bir ödül yoksa niye tırmansın? Google onu kullanıyormuş, Amazon bunu kullanıyormuş hiç bir önemi yok. İnsan en çok ağrıyan, en çok zonklayan kısma odaklanır. Google’ın başını en çok ağrıtan oymuş, ona bir çözüm bulmuş. Amazon’un en zonklayan tarafı buymuş, buna çözüm bulmuş. Eğer reçetemiz zonklayan bir ağrıyı dindirmiyorsa hasta yan etkilerini de göz önünde bulundurarak şüpheci yaklaşacak, verilen ilaçları sorgulayacaktır. Reçeteye ağrı değil, ağrıya reçete bulmak gerekir.

Geliştiriciler de bir nevi kullanıcılardır. İnşa ettiğimiz mimarilerin, geliştirdiğimiz altyapısal kütüphanelerin, koyduğumuz standartların kullanıcılarıdırlar. Bu manada kullanıcı deneyimi (UX) külliyatı geliştiriciler için de geçerlidir.

Kaynak: Google Çeviri: Çimenler çamur değilse, inşa ettiğiniz yol kayda değer bir fayda sağlamıyorsa, kullanıcılar neden kullansın ki?

Eğer her şeyi önceden tartmak mümkün olmuyorsa pilot bir çalışma yaparak daha dar bir kapsamda uygulamaya koyarız. Sonuçlarını, geleceğini, yaygınlaşmasını bu pilot çalışmaya bakarak değerlendiririz. Pilot çalışma başarılı olursa yaygınlaştırırız. Başarısız olarak değerlendirilirse bu şartlarda kullanımını sonlandırırız. Bunu da dar ve durağan bir bakış açısıyla bakarak, kurum için başarısızlık veya kayıp olarak değerlendirmemek gerekir. Her durumda analitik düşünen ve işleyen bir kurum kazanmış olur, bilgi birikimi ve tecrübe edinmiş olur. Bu da ilerleyen zamanlarda vereceği kararlarda ona yol gösterir.

Teknik Sunumlarda Mikroservislerin Ele Alınış Biçimine Dair Bir Eleştiri

Ne zaman bir teknik sunum izlesem hep aynı noktadan yaklaşıldığını görüyorum: “Altyapımızı nasıl mikroservislere geçirdik, mimarimizi nasıl dönüştürdük.” Sonra kullanılan araçlardan, karşılaşılan bir takım problemlerin nasıl çözüldüğünden bahsediliyor. Ama bu mimari geçişten beklenen katma değer neydi, ne kazanıldı, ne kaybedildi, kazanılması umulan şeyler hakikaten kazanıldı mı, performans arttı mı, hatalar azaldı mı, çeviklik arttı mı, kuruma finansal bir kazanç sağlandı mı, geliştirmeler ve bakım kolaylaştı mı? Genellikle bu konulardan pek bahseden olmuyor. Geçiş süreci de kendi başına değerli ve anlatılmayı hak ediyor tabi ki, ama en önemli kısım eksik kalıyor.

5N1K denir, bir vakayı incelerken sorulması gereken soruları ifade eder: Kim, Ne, Nerede, Ne zaman, Nasıl, Neden, Ne belli, Nolmuş, Neyi, Neye, Kimi, Kaçta. Bu soruların ilk beşi yanıtlanır da, altıncısı “Neden”e vurgu yapan pek olmaz. Bu en zor, cevaplanması en meşakkatli ancak en önemli sorudur.

“Neden?” sorusu o kadar önemlidir ki, “5 kez neden diye sorma” tekniği geliştirilmiştir, bir problemin kök sebebini bulmak için.

__ Mikroservis mimarisine geçmeliyiz.

__ Neden?

__ Uygulamanın performansı iyi değil, geç cevap veriyor.

__ Neden?

__ Çünkü tüm istekler aynı veri tabanına gidiyor, veritabanı kaldırmıyor.

__ Neden?

__Dikey ölçekleme yaptık, partioning yaptık, ancak ilişkisel ACID veritabanı kullandığımız için yazma işlemleri için ölçeklemenin de bir limiti var, bu limite takılıyoruz.

__ Neden?

__Her makinenin fiziksel bir okuma/yazma sınırı var. Hiç bir makine sonsuz büyüklükte bir işlem kapasitesine sahip değil. Mikroservis mimarisine geçersek her modül için ayrı bir veritabanı olacak. İşlem yükünü dağıtmış olacağız.

Yukarıdaki yapay senaryoda 4 tane neden diye sorulmuş durumda. Ek olarak problemin ne zaman oluştuğu, her zaman mı yoksa belirli günlerde mi oluştuğu vb. niceliksel ve niteliksel sorularla irdeleyip problemin çerçevesini anlamak, uygun çözümler üzerinde çalışmak, kafa yormak mümkün.

Bir karar verirken, yeni bir aracı kullanırken, yeni bir mimariye geçerken belki de en önemli sorudur “Neden?”. Çünkü problemin ve çözümün varlığına yani ontolojisine dair bir şeydir. Uygulama sonrası hedeflenen amaca ulaşıldı mı diye de kontrol edilmesi gerekir. Bunun için de öncesi ve sonrasına dair ölçümlemeler ve karşılaştırmalar yapmak gerekir. Aksi varsayımlar denizinde amaçsızca sürüklenmektir. Önce çalıp sonra kılıfını uydurmaktır.

Mikroservislerin Tarihçesi

Mikroservislerin tarihçesi konusunda farklı rivayetler bulunmaktadır. Bir rivayete göre Hammurabi bir gün Babil’in ünlü asma bahçelerinde oturmuş, ziyafet sofrasının kurulmasını bekliyormuş. Bir anda üç yüz saray hizmetçisi doluşmuş bahçeye. Bir yandan masaları ve sandalyeleri yerleştirmeye çalışıyorlarmış, bir yandan da yiyecek ve içecekleri tutuyorlarmış; çalgıcılar ve soytarılar da aralarında bekleşmekteymişler. Tam bir kargaşa ve keşmekeş hakimmiş. Düzeni ve yasa koymayı çok seven Hammurabi, bu duruma çok kızmış. Bundan sonra kim ki küçük küçük servis yapmaz, mikro mikro servis yapmaz, boynu vurula demiş. O günden sonra işleri, ayrı küçük ekipler halinde parçalara bölerek düzenli bir şekilde yapmak kural olmuş. Bu kural nesiller boyunca mikroservis yasası olarak anılagelmiş. Gidenler bilir ki, Hammurabi’nin anıt mezarının yüksek sütununda büyük harflerle şöyle yazmaktadır: “Mikroservis: Peki ne kadar küçük? Bir pizzayla doyacak kadar tabi ki! Çünkü açken sen sen deyılsın!!”

Mikroservislerin tarihçesi konusundaki bir diğer rivayet ise “Mikroservis” teriminin ilk kez 2011'de bir yazılım mimarisi çalıştayında ortaya atıldığı şeklinde. Bu mimari o sıralarda Amazon ve Netflix gibi şirketler tarafından farklı isimler altında fiilen uygulanmaktadır. O sıralar Netflix kendi mimarisine “Küçük Taneli SOA” (fine grained SOA) demektedir. Servis odaklı mimariler (SOA) fikri daha eskilere dayanmaktadır. Ancak daha çok büyük teknoloji tedarikçilerinin pazarlama ve müşterilerini kendi sistemlerine bağımlı kılmalarının bir aracı haline gelmiştir. Esneklik ve birbiriyle uyumluluk sorunları olan, kullanıcılarını kendine bağımlı kılarak hapseden ESB (Enterprise Servise Bus) ürünlerini ifade eder hale gelmiştir. Sistemi bileşenlerine ayırarak yönetme fikri ise 1960'lara kadar gitmektedir. Bağımsız ve ortagonal modülleri farklı kombinasyonlarda bir arada kullanmanın ilk ve en güzel örneklerinden biri Unix pipes’dır. Komut satırı komutlarının pipe ile pipeline oluşturarak kullanılması: dosyayı oku | küçük harfe çevir | noktalama işaretlerini sil | yeni dosyaya yaz. Benzer şekilde nesneye yönelik programlama ve fonksiyonel programlama da her ne kadar farklı paradigmalar olsalar da uygulamayı alt parçalara ayırarak daha kolay bir şekilde yönetme felsefesinden hareket etmektedirler.

Mikroservislerin Artıları ve Eksileri

Son zamanlarda satış ve pazarlama bağlamında duyduğum ve çok sevdiğim bir ifade var: “Özelliğe değil faydaya odaklan”. O özelliği de varmış, bu özelliği de varmış. Kes kardeşim. Boşver. Bana ne faydası var onu söyle. Süslü süslü laflar edip durma. Bu benim hangi derdimi çözecek? Ne fayda sağlayacak? Çözülmesini şiddetle arzuladığım bir problemimi mi çözecek, yoksa var olmayan bir problemimi mi çözecek? Yoksa aldığın bir sufleyi, okuduğun yüzeysel bir bilgiyi tekrar mı ediyorsun?

Özelliğe değil de faydaya odaklanmak ifadesi bana canlı pratiğe değil geride yatan prensiplere hatta onların da gerisindeki değerlere odaklanmayı anımsatıyor. Pratikler ve araçlar çok hızlı değişir. Prensipler daha az, daha yavaş değişir. Değerler ise pek değişmez.

Peki mikroservislerin faydaları neler? Sunduğu değerler neler? Pek çok fayda sayılabilir. Fakat yazma işlemlerinin yoğun olduğu büyük ve girift bir sistemde kullanımı konusunda karar verirken evet/hayır noktasına gelinmişse bence beraberliği bozacak olan fayda ölçeklenebilirliktir. Diğer faydaları başka mimari yaklaşımlar da sağlayabilir, ancak mikroservislerin veritabanlarının ayrı olması sebebiyle getirdiği en fark yaratan faydası ölçeklenebilirliktir.

  • Ölçekleme: Makinelerin disk, işlemci, bellek, bant genişliği bakımından fiziksel bir limiti vardır. Makineyi sonsuza kadar büyütemezsiniz. Yapabileceğiniz şey parçalara bölerek işlemleri dağıtmaktır. Yerel yönetimler gibi. Mikroservis mimarisi her servis için ayrı bir veritabanı öngördüğü için otomatik olarak yük dağılmış, işlem hacmi limiti artmış olur. Sistemi parçalara ayırdığınızda, okuma/yazma karakterine göre, işlem niteliğine ve zamanına göre, işlem hacmine göre belirli parçaları farklı şekilde ele alabilirsiniz, farklı teknolojiler, alt mimariler (senkron/asenkron yapılar) kullanabilirsiniz. Farklı servisler için farklı sanal/fiziksel makineler kullanabilirsiniz. Farklı servisler için farklı sayıda uygulama kopyası (instance) çalıştırabilirsiniz.
  • Modülerlik: Bazen modülerlik denmek istenir belki de, fakat mikroservisler denir. Aslolan modülerliktir. Mikroservisler modülerliğin bir uygulama biçimidir. Modülerliği, sistemi servis seviyesinde parçalayarak sağlar. Monolitik uygulamalarda da modülerliği sağlamak mümkündür. Eksiğiyle veya gediğiyle. Örneğin Java’da jar’lar, .NET tarafında dll’ler ve dinamik bağlama (dynamic binding) ile sistemi parçalayıp bağımsız olarak ayrı ayrı taşımak mümkündür. Mikroservisler, servis seviyesinde ayrıştırma yaparak, sınırları belirginleştirir, bağımlılıkları azaltır, izolasyonu sağlar, böylelikle modülerliği daha bir vurgular.
  • Bağımsız Taşıma: Uygulama servis bazında parçalandığı için her bir alt servis veya uygulama birbirinden bağımsız olarak taşınabilir. Aradaki bağ artık servis kontratıdır, servis API’sidir. Bu kontrat değişmediği sürece içeride istediğin gibi at koşturabilirsin. İstediğin değişiklikleri yapabilirsin. İstediğin zaman taşıyabilirsin. Diğer parçalarla tek paylaştığın şey servis kontratıdır. Servis kontratı geriye dönük uyumsuzluk yaratacak şekilde değişmediği sürece hiç bir değişiklik sorun yaratmayacaktır.
  • Teknoloji Heterojenliği: Farklı servislerde farklı diller ve teknolojiler denemeyi mümkün kılar. Ancak uzun vadede çok farklı diller, teknolojiler kullanmak ek bakım maliyetleri getireceğinden çok da tercih edilmez. İnsanlar çoğu kez bu maliyetleri göz ardı edip, yeni teknoloji şehvetine kapılsa da analitik düşünüp getiri götürü ekseninde rasyonel karar verenler bu noktaları hesaba katarlar.
Kısa Çeviri: Keşke tek bir dil, tek bir teknoloji olsa da hayat kolay ve üretken olsa. :)
  • Dayanıklılık: Uygulama alt parçalara ayrıldığı ve ayrı process’lerde ayrı servisler olarak çalıştığı için, bir yerdeki hata sistemin çökmesine sebep olmaz. Sadece o servis ve diğer servislerin ona bağımlı olan fonksiyonları etkilenir. Geriye kalan kısımlar işlemeye devam eder. Geleneksel mimariler dayanıklılığı, farklı kanallar için farklı uygulama kopyaları (BulkHead yöntemi) çalıştırarak yönetmeye çalışır. Örneğin bankacılık uygulama mimarisinde mobil, internet, şube vb. kanallar için ayrı uygulama kopyaları çalıştırılır ki, bir kanala ait istek hacminden veya hatalardan diğeri etkilenmesin. Mikroservis mimarisinde ise bir alt servisteki hatanın diğer servisleri aşağı çekmemesi için devre kesici (Circuit Breaker) yöntemi ve yine farklı kanallar için farklı izole kopyalar çalıştırma (BulkHead) yöntemi uygulanabilir.
  • Organizasyonel uyum: Conway kanunu uygulama mimarisi ile organizasyonel mimari arasında bir etkileşim olduğunu söyler. Organizasyonun inşa ettiği mimari yapının organizasyon yapısına benzeyeceğini iddia eder. Mikroservis mimarisi, uygulamalar ekiplere modüller halinde dağıtıldığı için organizasyon yapısıyla uyumlu bir mimari sağlamış oluyor. Modülerliğin sınırlarını belirginleştirdiği için. Bağımlılıkları azalttığı için. Bir kurumdaki en zor şeydir ekipler arası iletişim. Herkesin kendi gündemi, kendi öncelikleri oluyor. Bu da herkesin aynı sayfada olmasını, harmoni içerisinde hareket etmesini engelliyor. Bağımlılıklar ve koordinasyon ihtiyacı arttıkça hayat zorlaşır, çatışmalar ve sürtüşmeler artar.

Peki ya eksiler. Her çözüm beraberinde kendi problemlerini getirir. Mikroservislerin beraberinde getirdiği zorluklar ve problemler neler?

  • İşlem bütünlüğü problemi: Dağıtık sistemlerde işlem bütünlüğü konusu çözülmesi en güç ve karmaşık problemlerden biri olagelmiştir. Bu mikroservis mimarisi için de geçerlidir. Bir sonraki bölümde bu konu detaylı olarak ele alınmaktadır.
  • Karmaşıklık: Bir sürü servis, araç, yaklaşım, pratik. Bu dünyaya yeni giren birini korkutuyor. İnsan kullana kullana alışıyor gerçi. Eğer ortak kütüphaneler ve altyapılar geliştiricilere başarılı soyutlamalar sunuyorsa, insanlar çok kafa yormadan işlerini yapabiliyorlarsa, alışıyorlar bir şekilde bu karmaşaya. Ama henüz yeterince olgunlaşmamış bileşenler ve altyapılar varsa bunlarla uğraşmak baş ağrıtabiliyor.
  • PAAS platformu ve otomasyon ihtiyacı: Amazon şirketi AWS altyapısını dışarıya sunmak üzere inşa etmemiştir. Yüzlerce servis inşa etmek ve bunların operasyonunu kolayca yönetebilmek, ekiplerinin kendi servislerinin tüm yaşam döngüsünü kendilerinin yönetebilmesini sağlamak için oluşturmuştur. Yüzlerce servis demek tekrar eden yüzlerce benzer görev demek. Bunun optimizasyonu da ortak bir operasyon altyapısı oluşturmaktan geçiyor. Kendi içlerinde kullandıktan sonra, bu altyapıyı AWS (Amazon Web Services) olarak satmaya başlamışlar. Buradan da bugün Amazon, IBM, Microsoft, Google, Oracle gibi şirketlerin paylaşa paylaşa bitiremedikleri bulut sistemleri ortaya çıkmıştır. Docker gibi konteynır sistemleri, Kubernetes gibi konteynır yönetim sistemleri, OpenShift, WMware Tanzu (eskiden PCF) PAAS platformları bu operasyon kasını diğer şirketlere de sunar hale gelmiştir.
  • Merkezi log sistemi ve log takibi: Tek parça (monolitik) uygulamada loglar tek bir dosyaya yazılmaktadır. Mikroservis mimarisinde ise yüzlerce küçük uygulama olduğu için logları tek bir yere toplamak gerekmektedir. Bu ihtiyacı karşılamak için Elastic Stack benzeri uygulamalar kullanılmaktadır. Ayrıca farklı uygulamaların logları arasında korelasyon sağlamak ve dağıtık işlemlerin takibi için open-tracing vb protokoller ve araçlar kullanmak gerekmektedir. Bu konuyla ilgili detaylı bir inceleme için makaleyi inceleyebilirsiniz.
  • Problem çözümü ve takibin zorlaşması: Tek bir uygulama olunca problemin nerede olduğunu anlamak kolay oluyor. Ama onlarca uygulama olunca, araya asenkron iletişimler de girince takip etme, akışı anlamak, hata ayıklamak (debug) zor oluyor. Problem çözerken, problemin nereden kaynaklandığını anlamak, yerini tespit etmek güçleşiyor. Kağıt üzerinde kolay gözüken şeyler üretim ortamının öngörülemeyen istisnaları ve hızlı problem çözme baskısı altında baş ağrıtıcı olabiliyor.
  • Test otomasyon ihtiyacı: Monolitik uygulamada derleme ile yakalanabilen hatalar, modüller ayrı servislere ayrıldığında yakalanamaz hale geliyor. Bu da servis kontratlarının değişmediğinden emin olmak üzere kontrat testleri yazmayı ve bu testleri otomatik olarak taşımaların önüne koymayı gerektiriyor. Konuyla ilgili detaylar için makaleyi inceleyebilirsiniz.

İşlem Bütünlüğü veya Sen Dağıttın Sen Topla Meselesi

Problem basit aslında. Ama çözümü zor.

Tek parça geleneksel bir uygulamada işlem bütünlüğü meselesi basittir, oturmuş kullanılagelen bir yöntem bulunmaktadır herkesin bildiği.

Tek bir uygulama ve veritabanı olduğunda işler kolay. İşlem ya başarılıdır ya da başarısız.
Tüm işlem tek bir transaction bloğunda gerçekleşir.

Fakat birden fazla izole servise veya uygulamaya yazma yapılıyorsa işler karışır.

Resimdeki üç servis üç farklı mikroservisi temsil etmektedir. Bir işlemi yapmak için üç farklı servise yazılması gerekmektedir. Bu üç servis de farklı process’lerde çalışmaktadır, yani aynı DB nesnesini yani aynı transaction’ı kullanmaları mümkün değildir. Peki bu servislerden ikisi veritabalarına işlemi yazar üçüncüsü hata alırsa ne olacak? İşlem nasıl geri alınacak?

Geleneksel olarak bir uygulamadan harici bir servis çağrımı yapılacaksa tüm işlemler yapılır ardından harici servis çağrımı yapılırdı. Eğer servisten hata alınırsa hata (exception) fırlatılarak işlem (transaction) iptal edilirdi. Eğer hata alınmazsa commit yapılarak işlem tamamlanırdı. Burada ise üç, dört belki daha fazla sayıda servis bulunuyor. İşlem bütünlüğü ve tutarlılık nasıl sağlanacak?

Bir yol 2-phase-commit yöntemi. Dağıtık sistemlerdeki konsensus algoritmaları bağlamında ortaya çıkmış bir yöntem. En bilindik uygulamalarından biri JTA. Ancak Mikroservisler bağlamında ölçeklenebilirliği engellediği gerekçesiyle tavsiye edilmiyor. Tabi bir de servislerin bu protokolü destekleyecek biçimde yazılması gerekiyor.

Bir diğer yöntem ise Saga yöntemi. Bu yöntemde her servisin işlemi iptal edecek şekilde rollback metotlarını yazması gerekiyor. Her servisin tüm yazma işlemleri için geriye alma metotları sunması gerekiyor. A->B->C->D gibi karmaşık çağrımlar silsilesinde tüm geriye alma işlemi çok grift ve kırılgan bir yapıyı ortaya çıkarıyor. Ayrıca finansal bir sistemde geriye alma işleminin finansal anlamları olabilir ve hem iş birimince hem de düzenleyici kuruluşlar nezdinde istenmeyebilir. Dolayısıyla veri tutarlılığının çok hassas olduğu ve tutarlılığın ilişkisel veritabanlarının sunduğu seviyede olması istenen bir finansal sistem için bu yöntem uygun olmayabilir.

Üçüncü bir yöntem ise Event Sourcing. Bu yöntem DDD (Domain Driven Design) kapsamında ortaya atılan bir yaklaşım. Temel olarak veritabanının son halinin, küçük değişikliklerin toplamı olarak modellenmesini ifade eder. Fotoğraf karelerini üst üste koyunca video’nun oluşması gibi. Baştan sona oynatılınca tarih tekerrür etmiş oluyor, zaman yolculuğu gibi. Bu yöntem mikroservis mimarisinde ilişkisel veritabanları seviyesinde bir işlem bütünlüğü sağlamanın bir yolu olarak kullanılmaktadır.

Event Sourcing temsili. Like Stars on Earth (2007) filminden.
Genel olarak Event Sourcing

Bu yöntemde işlem bütünlüğü yönetici servisi işlemin başlangıç ve bitişine ait olay kayıtlarını olay veri tabanına yazıyor. Olay veritabanı, ilişkisel veritabanlarının veri tabanına yazmadan önce işlem bütünlüğünü, hatalara karşı dayanıklılığı sağlamak üzere kullandıkları commit loguna benzemektedir. Martin Klepmann bu mimariyle ilişkili olarak veritabanının içini dışına çıkarma anlamında “Turning the database inside out” demiştir. Yani veritabanının içeride kullandığı mekanizma dışarı çıkarılıp, servislerin üstüne bir katman olarak konulup, işlem bütünlüğünü sağlamada kullanılmaktadır.

Bu mimaride olay veritabanı, gerçeğin tek kaynağı (single source of truth), yani asıl veritabanı olarak işlev görmektedir. Kayıtlar, olaylar şeklinde tutulmaktadır. Tüm kayıtlar baştan sona işlendiğinde son durum ortaya çıkmaktadır. Buradaki kayıtların ilişkisel veri tabanına materializer uygulaması üzerinden aktarımı ise gerçeğin farklı yüzleri gibidir. İlişkisel veritabanlarındaki tablo ile view ve materialized view ilişkileri gibi.

Bir bakıma bu mimari, dağıtılan servislerin işlem bütünlüğünü sağlamak üzere, bir üst katman aracılığıyla toplanmasını ifade etmektedir. Hadi sen dağıttın sen topla gibi bir nevi.

Event Sourcing: Başarılı işlem örneği
Event Sourcing: Hatalı işlem örneği
Bir servis için Event Sourcing ve Materializer üzerinden veri akışı
Materiazer’ın işleyişi

Event Sourcing Yöntemi ve Mikroservislerin Kullanımının Değerlendirilmesi

Sistem işliyor mu? Evet. Karmaşık mı? Evet. Kritik sistemlerde kullanım için yeterince olgun mu? Hayır.

Veritabanı yönetim sistemleri yıllardan beri var. Oturmuş pratikler, olgun araçlar, üretkenliği artıran bütünlüklü bir ekosisteme sahipler. Var olan uygulamalar bu sistemlere göre tasarlanmış durumda. Geliştiriciler, veri tabanı ekipleri, sistem yönetimi, iş birimi, teknik ve iş süreçleri hep var olan sistemlere göre tasarlanmıştır.

Veri yönetimiyle ilgili yeni bir mimari oluşturmaya kalkınca, önceden çözülmüş problemlerin teker teker yeniden çözülmesi gerekiyor:

  • Olay veri tabanına yazılan kayıtların geriye dönüşü yok. Olayları yayınlamadan önce şema kontrolü (tip, uzunluk, tekillik vb. kısıtlar) yapmak gerekiyor.
  • İlişkisel veritabanlarının varsayılan izolasyon seviyesi olan “Read committed” seviyesini sağlamak için materializer ile ilişkisel veritabanına aktarılmış kayıtları okuyup üstüne olay veri tabanındaki henüz işlenmemiş committed, ve uncommitted işlemleri almak gerekebiliyor. Aynı transaction içindeyse işlenmemiş bir transaction’ı görmek, farklı transaction içindeyse görmemek gerekebiliyor.
  • İşleme konu olan varlıklar (satırlar bir nevi) için global bir kilit (lock) mekanizması kurmak gerekebiliyor.
  • Coğrafi yedeklilik için olay veritabanının offset bilgisi değişmeden nasıl klonlanacağını düşünmek gerekebiliyor.
  • Olay veri tabanından ilişkisel veri tabanına aktarımda bir şekilde hata çıkarsa ne yapılacağını, olay kaydı işlenirken hep hata alınıyorsa ne yapılacağını düşünmek gerekiyor. Hep hata veren kayıtları ayrı bir kuyruğa almak gerekebiliyor. Hata yönetim mekanizmalarını kurgulamak, gerekli araçları oluşturmak gerekiyor.
  • Toplu işlemlerin nasıl modelleneceğini düşünmek gerekiyor.
  • Uygulama üzerinden gidilmeden yapılan veri güncellemelerinin nasıl olacağının düşünülmesi gerekiyor.
  • Yaşamakta olan eski sistem ile yeni oluşturulmaya çalışan sistemin iki koldan bir arada tutarlı bir şekilde nasıl çalışacağını düşünmek, aradaki mekanizmaları kurmak gerekebiliyor.

Senelerce kullanılmış, oturmuş, olgun bir sistem olmayınca temkinli ilerlemek gerekiyor. Kaleleri adım adım fethetmek gerekiyor. Problemleri adım adım çözmek gerekiyor. Delikleri teker teker kapamak gerekiyor. Yavaş yavaş sistemi olgunlaştırmak gerekiyor.

Bir noktada karar vermek gerekiyor. Eğer sistem sadece okuma yapan bir sistem olsa istediğin kadar böl parçala. Çünkü bölmek hakikaten sistemin yönetilebilirliğini artırıyor. Ama yazma işlemleri işin içine girince işler karışıyor. Eğer veri tutarlılığı çok hassas değilse Eventual Consistency ile ilerlemek mümkün olabilir. Fakat eğer girift, karmaşık, büyük, işlem yoğun ve veri tutarlılığının hassas olduğu (Strong Consistency) bir sisteme sahipsek bu yöntemi kullanmak için en başımızı ağrıtan problemin ölçekleme problemi olması gerekiyor. Aksi halde insanlar ne gerek var bu sisteme, bunca karmaşıklığa, oturmamışlığa, zorluğa diyor haklı olarak. Eğer zonklayan ağrı ölçeklenebilirlik olursa muhtemelen yan etkilerini bile bile ilacı içmeyi kabul edecekler. Bu da bizi keskin bir ayrıma götürüyor. İşlem yoğun, yüzlerce modül, yüzlerce kolon içeren binlerce tablodan oluşan grift, karmaşık, veri tutarlığı bekleyen büyük bir sistemi mikroservislere dönüştürelim mi dönüştürmeyelim mi? Ölçeklenebilirlik problemin varsa dönüştür, yoksa dönüştürme. Yazma işlemin yoksa dönüştür, varsa dönüştürme. Başka modüle ihtiyaç duymayan yekpare parçalar varsa onları dönüştür, mümkün mertebe dağıtık işlem bütünlüğünden kaçın.

Bitirirken

Bir şeyi söylemek farklı yapabilmek farklıdır. Beynimizin bilmesi kaslarımızın bildiği anlamına gelmez. Kullanılmayan bilgi yükünün yürürken sırtımızdan yavaş yavaş dökülmesi bundandır. Okunan onlarca kitaba rağmen durup heybemize baktığımızda çoğunun orada olmaması bundandır.

Analitik düşünmekten ve davranmaktan dem vurmak analitik olabilmeyi sağlamaz. Soru sormayı alışkanlık haline getirmek ve sorgulama kasını çalıştırmak gerekir.

Çoğu kez varsayımlar, eksik bilgi, ön yargılar ve psikolojik sebeplerle analitik davranmayız. Bazen fark ederiz hatamızı, utanırız, kendimize kızarız. Sorgulayan, soru sormayı becerebilen, bilgiyle, getirisini götürüsünü tartarak karar vermeye çabalayan biriyle karşılaştığımızda da hayranlık duyarız.

Bence ilk okuldan itibaren konması ve her yıl işlenmesi gereken bir ders analiz ve analitik düşünme. Günümüz insanının en büyük sorunu analiz etme, değerlendirme, soru sormayı bilme, doğru soruları sorabilme.

Iyyyy… Monolith… Veya zamanın ruhu. Neyin iyi neyin kötü olduğu hakkındaki hükmünü açıklayan toplumsal kabul rüzgarlarında bir yaprak gibi savrulmak. Veya kendi kararını ihtiyaç analizi temelinde verme yetisinin kaybı. Veya kelimelerin büyüsüne kapılıp gitmek.

--

--