# MikroServis Mimarisi

Doğru aracı doğru zamanda ve doğru şekilde kullanmak, yazılım geliştirme sürecinin en önemli ve de en çok tecrübe gerektiren konularının başında gelir. Burada ki '**araç**' ile;  bir tasarım kalıbı, bir programlama dili, bir veri tabanı, bir algoritmadan tutun, seçtiğiniz bir CI yazılımına kadar çok geniş bir yelpazeyi düşünmelisiniz. Bunların her birisine, sizi amacınıza ulaştıracak olan birer araç gözüyle bakmalısınız.&#x20;

Mikroservis Mimari de hedefe giden yolda seçebileceğimiz araçlardan bir tanesi. Ancak bu seçimi yaparken bunun sadece teknik bir karardan ibaret olmadığını, aslında organizasyonel bir yönünün olduğunu da unutmamamız gerekiyor. Yani mevcut ekip veya ekiplerinizin bu mimariyi uygulamak için uygun bir yapıda olması gerekmekte. Uygun yapıda olmaktan kastımızı bir sonraki bölümde detaylandıracağız.

Mikroservis Mimari'yi, temel prensiplerine sadık kalarak en doğru şekilde uyguladığımızda getirdiği avantajlardan faydalanırken, yanlış ve yersiz kullanımı ise hem zaman hem de kaynak israfıyla sonuçlanacaktır. Bu yüzden işe koyulmadan önce tüm detaylarıyla tartışılması gereken, çok önemli bir karar olduğunu unutmamalıyız.


# Yol Haritamız

Mikroservis Mimari’ler İçin Yol Haritası

**Mikroservis Mimari** 2011 yılındaki ilk telaffuzundan bugüne kadar popülerliğini gün geçtikçe artırd&#x131;**.** Birçok ekip mevcut **Monolith** uygulamalarının yenilenme sürecinde veya yeni başlanacak projelerde Mikroservis Mimari’yi tercih etmeye başladı.Bu bölümde, bu mimariyi uygulamadan önce bilmemiz gereken konular ve işe koyulduktan sonra bizleri nelerin beklediğine dair önemli noktalara değineceğiz.

Konuyu aşağıdaki 4 başlık altında inceleyeceğiz;

* Uygulamanın Mikroservis Mimari’ye Uygunluğu
* Mikroservis Mimari’ye Geçiş İçin Hazır mıyız?
* Mikroservis Mimari’yi Uygularken Yapılan Hatalar
* Tavsiyeler

## Mikroservis Mimari’yi Uygulamalı mıyız? <a href="#ff9a" id="ff9a"></a>

Bu çok önemli soru üzerinde belki de günlerce düşünüp konuşmak gerekirken, buna lüzum dahi görmeden biraz da gaza gelerek,  “**Mikroservis Mimari’ye geçiyoruz !**” diyerek, yeterli ar-ge yapmadan kolları sıvayan bir çok ekip olduğuna eminim. Aksi halde bu kadar “**başarısızlık hikayesi**” ortaya çıkmazdı diye düşünüyorum. Bu başarısızlık hikayelerinin anlatıldığı bazı makalelere, arama motorları üzerinden aratarak sizlerde kolayca ulaşabilirsiniz.

Bu bölümde madde madde “**Mikroservis Mimari’yi Uygulamalı mıyız?**”sorusuna nasıl cevap aramamız gerektiğine bakacağız. Eğer burada bahsedilen sorunlar veya iyileştirmeler sizin için geçerli değilse Mikroservis Mimari’yi uygulamak için geçerli bir sebebiniz yoktur diyebiliriz.

**Belirli Bir Teknoloji / Dil Ekosisteminde Sıkışmak**

İçerisinde çeşitli modüller barındıran **monolith** yapıda bir uygulama düşünelim. **Monolith** yapıdan dolayı tüm kodumuz tek bir proje yani tek bir **repository** içerisinde.

Talep doğrultusunda projenize yeni eklenecek olan bir özellik için görüntü işleme yapmanız gerekiyor. Kullanıcılarınızın ara yüzden yükleyeceği araba fotoğraflarından plaka tanımlaması yaparak sisteminizde bu plakanın kayıtlı olup olmadığına bakmanız gerekiyor. Bu durumda uygulamayı geliştirdiğiniz programlama dili ve teknolojilerle bu özelliği geliştirmeniz gerekmekte. Eğer diliniz bu iş için pek elverişli bir dil değilse, hem geliştirme eforunuz artacak hem de belki ciddi performans sorunları yaşayacaksınız.

&#x20;Bu işlemi yapan bağımsız bir servis geliştirelim, ve bu servisi istediğimiz farklı bir dille (**go**, **python** vs..) geliştirerek hem performans kazanımı elde edelim hem de teknoloji **stack**’ imizi genişletelim diye düşünmeye başladıysanız, Mikroservis Mimari sizin için uygun **olabilir.**

**Yüksek Ölçeklenebilirlik**

Yok biz böyle iyiyiz dediniz **monolith** yapıda devam ediyorsunuz ve kullanıcı sayınız da gün geçtikçe artıyor. Derken bizim görüntü işleme modülünün çok geç yanıt döndüğü şikayetleri gelmeye başlıyor. Mimariyi, gelen image’ leri kuyruklayıp tek tek kuyruktan alarak işleme üzerine kurmuşsunuz. Önceleri performans sorununuz yokken sisteme bir **t** anında yüklenen fotoğraf sayısı arttıkça kuyrukta bekleme süreniz de  uzadı ve neticede kullanıcılarınız mutsuz.

Bu durumda sunucunuzda kaynak arttırımı yapıp, uygulamanızı dikey ölçekleyebilir (**bir yere kadar**) veya bir kaç sunucu daha devreye alıp yatay ölçeklendirmeye gidebilirsiniz. Peki görüntü işleme modülü dışında kalan modüllerde de bu ölçeklenme ihtiyacı söz konusu mu? Cevabınız hayır ise, tek bir servisi dilediğinizce yatay/dikey ölçekleyebilme imkanını elde edeceğiniz Mikroservis Mimari’yi düşünebilirsiniz.

**Kolay ve Hızlı Release Çıkabilme**

“**En ufak bir değişiklikte koca uygulamayı olduğu gibi deploy ediyoruz**” tarzı cümleler kurmaya başladıysanız, veya geliştirme süreci tamamlanan ve acilen devreye alınması gereken bir özelliği, projedeki bağımlılıklardan ötürü yeterince hızlı bir şekilde devreye alamıyorsanız, sizin gözünüz gibi bakıp büyüttüğünüz monolith uygulamanızın irili ufaklı servislere bölünme zamanı gelmiş **olabilir**.

## Mikroservis Mimari’ye Geçiş İçin Hazır mıyız? <a href="#e077" id="e077"></a>

Önceki bölümde bahsettiğimiz konulardan sonra bu mimariye ihtiyacınız olduğuna kanaat getirdiniz. Peki nereden başlamalısınız? Yine madde madde inceleyelim;

**Güçlü Bir DevOps Ekibi**

Mikroservis Mimari’yi uygulayabilmek için en önemli şeylerden birisi hatta belki de en önemlisi DevOps kültürünün benimsendiği ve hakkıyla uygulandığı bir ekip veya ekipler oluşturabilmektir.

Martin Fowler, Mikroservis Mimari'nin getirdiği operasyonel yükü taşıyabilmenin güçlü bir DevOps takımına sahip olmaktan geçtiğini söyler. Öncelikle, servislerinizin building, configuration ve deploying süreçleri için bir **CI/CD pipeline’ı** tasarlamanız ve hayata geçirmeniz gerekiyor. Aksi halde çok fazla operasyonel yükle karşı karşıya kalabilir, dolayısıyla çok fazla vakit (**nakit**) kaybına uğrayabilirsiniz.

İlk etapta bazı süreçleri manüel yürütebilirsiniz belki. Ancak servis sayınız arttıkça ve **production** ortamınızı hazırlama zamanı geldiğinde artık **full-automated** olmanız gerekecektir.

**En Az Bir Cloud Provider Üzerinde Uzmanlaşmak**

Servislerinizi **on-premise** olarak kendi organizasyonunuz içerisinde kendi alt yapı ve ekipmanlarınızla yayınlayabilirsiniz elbette. Her ne kadar tavsiye edilen yöntem bu olmasa da en azından ilk etapta bu şekilde ilerlenebilir.

Ancak ilerleyen zamanlarda ürününüz **live** olmadan önce bir **cloud provider** (aws, google cloud, azure vs.) ile, cloud-based mimariye geçerek, hem operasyonel yükünüzü azaltıp hem de çok trafiği olan servisleriniz için **auto-scale** tarifeyi uygulayabilirsiniz. Bizim sunucular ayakta mı, ram/cpu yetersiz mi kaldı gibi soruları hayatınızdan çıkarmak sizin elinizde.

**En Az Bir Container Teknolojisi Üzerinde Uzmanlaşmak**

**Container** ve **Container Orchestration** araçlarının kaynak kullanımı ve ölçeklenebilirlik konuları başta olmak üzere bizlere kazandırdıkları hepimizin malumu. Monolith yapıdaki bir uygulamada, yani tek bir uygulamamız varken bile fayda sağlarken, söz konusu Mikroservis Mimari olduğunda adeta vazgeçilmez bir hal alıyor demek herhalde abartı olmaz.

‌Yine ilk etapta bir Container teknolojisi olmaksızın da ilerlenebilir. Mikroservis Mimari’nin benimsenmesi ve prensiplerine uygun şekilde hayata geçirilmesinin ardından, sıra deployment mekanizmasını değiştirmeye geldiğinde sanal makinalardan container’lara geçiş süreci başlatılmalı ve ardından bir container orchestration aracıyla dönüşüm tamamlanmalıdır. Sanal makinalar yerine Container'ları kullanmanın avantajları bu yazının konusu olmadığından burada kesmekte fayda görüyorum.

**Gelişmiş Monitoring ve Notification Araçları**

Birbirinden bağımsız olarak hayatına devam eden ve uygulamanın büyüklüğüne göre onlarca hatta yüzlerce sayıda olabilen mikroservis’lerin anlık olarak monitor edilebilmesi son derece önemlidir. Bu servislerden herhangi birinde meydana gelecek bir sorunun en hızlı şekilde ilgili yerlere sms, e-mail vb. gibi kanallardan bildirimi, sorunun hızlıca çözümü ve uygulamanın hayatını sürdürebilmesi adına çok kritiktir. Dolayısıyla Mikroservis Mimari’yi uygulamadan önce bu ihtiyaca cevap verebilecek bir monitoring aracının da devreye alınması veya en azından ön araştırmasının yapılması şarttır.

Bu monitoring ve alert ihtiyacı için kullanılabilecek bir çok ücretli veya ücretsiz açık kaynak araç mevcuttur.

**Her Mikroservis İçin İzole Bir Veri Tabanı**

Mikroservis Mimari, her servisin kendine ait, diğer servisler tarafından doğrudan erişime kapalı, izole bir veri depolama alanı olmasını gerektirir.

**Monolith** bir uygulamanın servislere ayrıştırılması konusunda, veri tabanı kısmı ilk etapta pek düşünülmeyebiliyor. Servisler şekillenmeye ve monolith yapıdan kopmaya başladıkça veri tabanlarının izolasyonu konuşulmaya başlanıyor. Tam bu noktada mevcut veri tabanının büyüklüğü ve tasarım kompleksliği aşılması gereken büyük bir sorun olarak karşımıza çıkıyor. Eğer bu sorun bir şekilde aşılamazsa, ya Mikroservis Mimariden vazgeçiliyor (servisleri ayrıştırmak için boşa harcanan efor), ya da izole veri tabanı konusundan taviz verilerek her servis ortak bir veri tabanını kullanacak şekilde ilerleniyor, ki bu Mikroservis Mimari'nin temel prensiplerinden olan "bağımsızlık" prensibine aykırı bir durum. Bu yüzden Mikroservis Mimari’ye dönüşümde ilk önce veri tabanı kısmını tasarlamak ve mevcut veri tabanının servislere özel olarak ayrışıp ayrıştırılamayacağı, bu işin eforunun ne olacağı konusunda biraz kafa patlatmak gerekiyor.

## **Mikroservis Mimari’yi Uygularken Yapılan Hatalar** <a href="#cfa1" id="cfa1"></a>

Bu mimariyi uygularken zaman içerisinde mimarinin temelini oluşturan prensipler ihlal edilebiliyor. Bunu iki nedene bağlayabiliriz. Birincisi temel prensipleri tam olarak anlayıp benimsemeden, aceleyle işe koyulmak. İkincisi, izole veri tabanı başlığı altında bahsettiğimiz istemeden de olsa bilinçli olarak verilen veya verilmek zorunda kalınan bazı tavizler. Şimdi bu mimariyi uygularken aklımızın bir köşesinde sürekli tutmamız gereken önemli noktalardan bahsedelim;

**Servisler Arası Ortak Kütüphane (library) Kullanmamaya Çalışın**

“E hani **DRY (don’t repeat yourself)** prensibine ne oldu? Aynı kodları her serviste tekrar tekrar yazacak mıyız?” diye düşünebilirsiniz.

Öncelikle tekrarlı kod oranımızı mümkün olduğunca azaltmamız gerekiyor tabi, **DRY** prensibinde bahsedilen konu **bussiness logic**’i içeren kod parçacığının sadece bir kere yazılması. Ancak Mikroservis Mimari'de işler biraz değişiyor. Eğer ortak kullanılan fonksiyonlarınızı bir kütüphane haline getirir ve servislerinizi bu kütüphanelere bağımlı hale getirirseniz mikroservice mimarinin sağladığı en büyük kazanımlardan birinden bir miktar taviz vermiş olacaksınız. Bu kazanım bir önceki bölümde prensip olarak dile getirdiğimiz, **bağımsızlık** prensibidir.

Unutmayın; bu mimaride her servis bağımsız olarak geliştirilip, yine bağımsız olarak **release** edilebilmelidir. Peki bu durumda servislerin ortak olarak kullandıkları kodlar için nasıl bir yol izlememiz gerekiyor? Şu 3 seçenekten birisini tercih edebiliriz;

1- **Servisler arası** tekrarlı kodu kabullen.(Bir noktaya kadar)

2- Ortak kodlar **business logic** içeriyorsa yeni bir **shared service** oluştur.

3- Eğer mümkünse, servisleri yeniden dizayn et ve yeni alt **Mikroservis**/ler oluştur.

**Bir Servisin Diğer Bir Servisin Verisine Erişim Yöntemi**

İzole veri tabanı maddesinde biraz bahsetmiştik, burada biraz detaylandıralım. İzole’den kasıt, bir servisin veri tabanına erişimin sadece o servis üzerinden olmasıdır. Yani bir servis başka bir servisin veri tabanına doğrudan erişim sağlayamaz, erişmesi gerekiyorsa veri tabanının sahibi olan ilgili servis üzerinden erişmelidir. Yani bir client gibi http isteğinde bulunmalıdır. Bu kuralda yine ihlal edilebilen kurallar arasında sayılabilir.

Genelde performans endişesinden dolayı yapılan bu hatada, **A** servisi **B** servisine istekte bulunmak yerine, doğrudan B servisinin veri tabanına erişerek, Mikroservis Mimarinin **gevşek** **bağlılık (loosely coupled)** prensibinin ihlaline neden olmaktadır. Bu ayrıca **A** servisi daha kompleks ve bakımı zor bir hale getirecektir.

**Authentication, Throttling Gibi İşlemlerin Merkezileştirilmemesi**

Bu maddeyi Throttling (**Rate Limiting**) üzerinden ele alabiliriz. Çok sayıda Mikroservis ’e sahip bir sisteminiz var ve her uygulamada olduğu gibi sizin uygulamanız için de client istatistikleri çok önemli. Hangi client veya hangi kanallardan (web, mobil) hangi servisler ne sıklıkla tüketiliyor? Hangi servislere daha çok yük biniyor? gibi soruların cevaplarını merkezi bir yapı üzerinden almak en doğrusu. Bu yapılar **Api Gateway** olarak adlandırılan servislerdir. Bu yapılar ile client’lardan gelen tüm istekler bir veya daha fazla olabilen api gateway’ler üzerinden ilgili servislere erişir.

Data önce deneyimle fırsatı da bulduğum **IBM’**&#x69;n **Datapower** isimli gateway’i ilk aklıma gelen örnek. Bunun yanında open source ve tamamen ücretsiz olan çok başarılı api gateway’ler de mevcut. (**Kong**, **Tyk** vs.)

Api gateway kullanılmadığı takdirde, Rate Limiting ve benzeri işlemler her servis özelinde tek tek geliştirilmek zorunda kalınacak ki bu da bir süre sonra servisleri daha kompleks bir hale getirerek bakım maliyetlerini artıracaktır. Bir diğer sorun tabi gereksiz harcanan efor olacaktır. Api gateway ile merkezileştirilebilecek işlemler, her yeni doğan Mikroservis için yeniden tek tek geliştirilmek zorunda kalınacaktır. Api gateway’ler oldukça yetenekli araçlardır, ve Mikroservis mimari’de kullanımlarının bir çok faydası vardır. Öyle ki tek başına ayrı bir yazı konusu olacak genişlikte olduğundan burada kesmekte fayda görüyorum.&#x20;

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F0j8MpmbNIo9qPjd055cb%2F001.jpeg?alt=media&amp;token=a704df7f-8a38-497c-bcb3-5dd13910d1bc" alt=""><figcaption></figcaption></figure>

## **Tavsiyeler** <a href="#id-9e4a" id="id-9e4a"></a>

**Startup’lar veya olgunlaşmış ekiplerdeki yeni başlanacak olan projeler için tavsiyeler;**

Eğer yazılım ekibiniz 2–5 kişilik bir ekipse ve ileride bu ekibi büyütme planlarınız yoksa, monolith başlamanızda fayda var. Zaten kısıtlı sayıdaki iş gücünüzü Mikroservis Mimari’nin getirdiği operasyonel yükün altında ezmek istemezsiniz.

Bu 2–5 kişilik ekibiniz için yakın zamanda büyüme planlarınız var, veya sıfırdan yeni ekip veya ekipler kuruyorsunuz diyelim. Bu durumda da aynı şekilde monolith olarak başlamanızı öneririm. Yani bana göre yeni uygulamalar için başlangıç her zaman monolith olmalı. Ekibiniz ve uygulamanız büyüdükçe, servislerinizin sınırları daha da netleşmeye başladıkça,  DevOps alt yapınızı oluşturup, mimari değişikliğe gidebilirsiniz.

**Monolith den Mikroservis Mimari’ye dönüşüm için tavsiyeler;**

Bu işi kesinlikle hafife almayın ve sizi neyin beklediğini iyice araştırmadan ilk kazmayı vurmayın. Yukarıda mümkün olduğunca özet haline getirmeye çalıştığım maddelerden her birisi, işe başlamadan önce ve başladıktan sonra bir şekilde karşınıza çıkacaktır emin olun.

Mikroservis  Mimari’ye dönüşümde Netflix’in hikayesi oldukça bilinen bir hikayedir. Monolith uygulamayı Cloud-Based **Mikroservis Mimari’**&#x79;e dönüştürme işine yanılmıyorsam 2009–2010 gibi başladılar ve bitirdiklerinde 2016 ya gelinmişti. Belki sizin sisteminiz bu denli büyük ve kompleks değildir, ancak işin ciddiyetini ve açılması gereken çok fazla kilit olduğunu Netfilix’in hikayesinden anlamak mümkün.

Toparlarsak; Mikroservis Mimari’ye girmek aslında DevOps kafasına girmek olmalı diyebiliriz. Sadece teknik değil, organizasyonel ve kültürel bir değişim gerektirdiğinin bilincinde olunmalı. Geliştiricilerin sürecin her aşamasında etkin rol oynaması gerekiyor. Eğer daha önce hiç Mikroservis  Mimari ve DevOps konuları hakkında deneyim edinmemiş bir ekip ile yola çıkıyorsanız, en azından temel konular hakkında bir eğitim ile işe başlamak bana göre elzemdir. Bu size vakit kazandıracağı gibi daha emin adımlarla ilerlemenize de imkan sağlayacaktır.


# Monolith'den Mikroservis'e

Mevcut Monolith Uygulamanın Mikroservis Mimari'ye Dönüşüm Serüveni

Bir önceki bölümde yeni bir projeye başlarken Monolith Mimari ile başlamanın daha doğru bir karar olacağını belirtmiş olsak da, Mikroservis Mimari ile başlangıç yapmak her koşulda yanlış olur gibi kesin bir ifade kullanmaktan da kaçınmalıyız. Dolayısıyla Mikroservis Mimari'ye geçiş için iki ana senaryomuz var diyebiliriz;&#x20;

İlki, mevcut Monolith Mimarinin dönüşümü ve diğeri doğrudan Mikroservis Mimari ile başlama.

İlerleyen bölümlerde detaylıca inceleyeceğimiz; Transaction Yönetimi, Servisler Arası İletişim, Veri Tabanı Tasarımı gibi konular her iki senaryo için de geçerli olmakla beraber, mevcut monolith mimarinin dönüştürülmesi senaryosu ekstra bazı zorluklar ihtiva etmekte. Bu bölümde biraz bunlardan bahsedeceğiz. **DDD ve Mikroservis Mimari** konu başlığında da bu dönüşüm konusuna atıfta bulunduğumuzu ayrıca belirtmek isterim.

## &#x20;Dönüştürme İşlemine Nereden Başlamalıyız?

Dönüşüm işleminin toplam süresi, dolayısıyla harcanacak toplam efor, uygulamanın bağımlılık ve karmaşıklık seviyesiyle doğrudan ilişkilidir. Birbirine sıkı sıkıya bağlı katmanlar ve modüllerden oluşmuş, ağırlıklı olarak iyi pratiklere uyulmadan geliştirilmiş bir uygulamanın dönüşüm sürecinin daha sancılı geçeceğini tahmin etmek zor değil. Bunun yanında modüler tasarlanmış ve gevşek bağlı, değişime kapalı ancak gelişime açık yapıdaki bir uygulamada ise işimiz daha kolay olacaktır. Buradan, modüler ve gevşek bağlı tasarımın ileride Mikroservis Mimari dönüşüm yapılması planlanan projeler için çok daha önemli hale geldiği sonucunu çıkarabiliriz.

Dönüşümü yapılacak olan uygulama hali hazırda kullanılmakta olan bir ürün ve mevcut monolith yapı üzerine aktif olarak geliştirmeler  ve hata ayıklama işlemleri devam ediyor. Haliyle tüm bu geliştirme sürecini durdurup, Mikroservis Mimari dönüşümünü yapma gibi bir lüksümüz olmayacaktır. Nefes alan, üzerinde aktif olarak geliştirme yapılan bir uygulamayı dönüşme gibi zorlu bir işimiz var.&#x20;

Bu dönüşüm işini 'kodları birbirinden ayırma' gibi basit bir seviyeye indirgemek yapacağımız ilk yanlış olacaktır. Öyle ki, kodları servisler halinde ayrışma işi bu dönüşüm sürecinin belki de en kolay işi olacaktır.&#x20;

Öncelikle kısa ve uzun vadelik eylem planları hazırlamamız gerekmekte. Mevcut monolith uygulamadan kaç adet servis doğacak, ve bu servislerin sınırlanır neler olacak soruları cevap bekleyen en zor sorular olarak karşımıza çıkacaktır. Bu sorularak nasıl cevap vermeliyiz, servislerin sınırlarını nasıl çizmeliyiz gibi konulara  **DDD ve Mikroservis Mimari** konu başlığında örnek bir senaryo üzerinden ele alacağımızdan, burada detayına girmiyoruz.

Uzun ve hararetli toplantılar sonunda servislerimiz ve bu servislerin sınırlarını belirledik. **Domain-Driven Design** ile ilerleyeceksek, Bounded-Context'lerimiz ve bunların sınırlarını doğru bir şekilde belirlemiş olmalıyız. Ne demiştik, mevcut monolith uygulama hayatına devam ediyor, öyleyse servislerimizi monolith yapıdan birer birer kopararak kontrollü bir şekilde devreye almamız gerekmekte.Dönüşümü tamamlayana dek, monolith bir uygulamamız ve belirli sayıda Mikroservis ile hayatımıza devam edeceğimiz anlamına geliyor bu.&#x20;

Burada kişisel bir tavsiye olarak şunu söyleyebilirim;  İlk servisi mümkün olduğunca basit ve ayırması kolay olan bir servis olarak seçmenizdir. Gerek servisi geliştirme süreci gerekse DevOps anlamında bu sizin acemilik döneminiz olacağından servisin basit olması hızlı çıktı almanızı sağlayacaktır.  Genelde benim aklıma ilk gelen notifikasyon servisi oluyor. Hemen her uygulamada, e-posta ve sms gibi bildirimleri göndermekle yükümlü bir modülümüz oluyor ve bu modülün pek bir bağımlılığı da olmuyor diğer modüllerle. Dolayısıyla notifikasyon işini yapmakla sorumlu modülü monolith yapıdan koparıp istediğiniz bir teknolojiyle servis haline getirerek başlangıç yapabilirsiniz. Eğer bu servis bir veri tabanına ihtiyaç duyuyorsa, mevcut veri tabanınızdaki ilgili tabloları ayrı bir ilişkisel veya NoSQL veri tabanına taşıyarak tam izolasyonu sağlayabilirsiniz. Her servisin mutlaka kendine ait bir izole veri tabanı olması gerektiğini unutmamalısınız. Veri tabanını servisler özelinde parçalama konusuna Veri Tabanı Tasarımı konu başlığında yine örnek bir senaryo üzerinden daha detaylı değineceğiz.

Bir diğer önemli nokta ise, dönüşüm sürecindeyken gelecek yeni bir talebin konumlandırılması konusudur. Konumlandırmadan kastımız geliştirmenin nerede yapılacağı. Burada 3 farklı ihtimal söz konusu;&#x20;

**a)** Mevcut Monolith    **b)** Mevcut Mikroservis'lerden birisi    **c)** Yeni bir Mikroservis

Eğer gelen bu yeni istek uygulamamız için tamamen yeni bir özellik anlamına geliyorsa yeni bir Mikroservis olarak geliştirmek önceliğiniz olmalı. Eğer mevcut modüllerden birisiyle bağlantılıysa doğru konumlandırmak o kadarda kolay olmayabilir. Eğer servis sınırlarımızı (Bounded Contex'lerimizi de diyebiliriz) doğru bir şekilde çizdiysek, bu 3 seçenek arasında en doğru olanı çok zorlanmadan bulabiliriz. Aksi halde her yeni gelen istek için bu 3 seçenek arasında kalma ve yanlış kararlar verme ihtimalimiz olacaktır. Bu yüzden servis sınırlarının doğru olarak çizilmesi konusu büyük öneme sahip.


# Transaction Yönetimi

Mikroservis Mimari’lerde Transaction Yönetimi

Bu bölümün başlığı için birkaç farklı seçenek arasından bir seçim yapmak durumunda kaldığımı itiraf edeyim. **Transaction Yönetimi**, **Transaction Bütünlüğü**, **Veri Tutarlılığı** (Data Consistency) vb. gibi kavramların aslında aynı kapıya çıktığını söyleyerek başlayabiliriz.

Konuyu aşağıdaki başlıklara bölerek anlatmayı uygun buldum;

* Transaction ve Transaction bütünlüğü nedir?
* ACID prensipler hakkında
* Monolith uygulamalarda transaction yönetimi
* Mikroservis Mimari'de transaction yönetimi
* Mikroservis Mimari’de transaction yönetimi için **Two-Phase Commit** ve **Saga** tasarım kalıpları
* **Two-Phase Commit** vs. **Saga**

## Transaction Kavramı

Transaction kelime anlamı olarak iş/işlem anlamına gelmekle birlikte kullanıldığı alana göre farklı anlamlar kazanabilmekte. Bankacılık sektöründe, yapılan bir EFT için kullanılırken, muhasebe dünyasında deftere yapılan her bir yazma işlemi için kullanılabilir. Veri tabanı üzerinde yapılan işlemlerin her birisi bizim için bir **transaction**’dır.

Bazı business transaction’lar, birden fazla transactionın çalışmasını gerektirebilir. Eğer Mikroservis Mimari söz konusuysa, bu aslında birden fazla servisin ard arda çalışması anlamına gelir. Bu arda arda çalışan transaction’lar dizisinin yönetilmeye ihtiyacı vardır. Yönetiminden kastımızın ne olduğuna bir örnek senaryo üzerinden bakalım.

Bir e-ticaret sitesinde bir ürünün siparişinden müşteriye teslim edilmesine kadar geçen sürede bir çok sürecin dolayısıyla transaction’ın işletildiğini biliyoruz.

Örneğin ödeme işlemi ve sonrasında ürünün stoktan düşülmesi süreçlerini ele alalım. Ödeme işlemi başarılı olmadan, stoktan düşme süreci ve sonraki süreçler işletilemez. Peki ödeme işlemi başarılı olduktan sonraki süreçlerin birisinde bir hata meydana gelirse ne yapmalıyız? Yazılım tarafında bu durumu nasıl yöneteceğiz? Bu hata oluştuktan sonra o ana kadar veri tabanı üzerinde yapılmış olan işlemlerin tümünü geri almak gibi bir sorunumuz var. İşte bu sorun ve çözümü **transaction bütünlüğü/tutarlılığı/yönetimi** konusunun temelini oluşturmakta.

## ACID Prensipler

ACID, değişikliklerin bir veri tabanına nasıl uygulanacağını yöneten 4 adet prensip sunar. Bunlar, **Atomicity**, **Consistency**, **Isolation** ve **Durability** prensipleridi&#x72;**.** Bir kaç cümle ile açıklamak gerekirse;

**Atomicity**: En kısa ifadesiyle ya hep, ya hiç. Arda arda çalışan transaction’lar için iki olası senaryo vardır. Ya tüm transaction’lar başarılı olmalı ya da bir tanesi bile başarısız olursa tümünün iptal edilmesi durumudur.

**Consistency**: Veri tabanındaki datalarımızın tutarlı olması gerekir. Eğer bir transaction geçersiz bir veri üreterek sonuçlanmışsa, veri tabanı veriyi en son güncel olan haline geri alır. Yani bir transaction, veri tabanını ancak bir geçerli durumdan bir diğer geçerli duruma güncelleyebilir.

**Isolation**: Transaction’ların güvenli ve bağımsız bir şekilde işletilmesi prensibidir. Bu prensip sıralamayla ilgilenmez.Bir transaction, henüz tamamlanmamış bir başka transaction’ın verisini okuyamaz.

**Durability**: Commit edilerek tamamlanmış transaction’ların verisinin kararlı, dayanıklı ve sürekliliği garanti edilmiş bir ortamda (sabit disk gibi) saklanmasıdır. Donanım arızası gibi beklenmedik durumlarda transaction log ve alınan backup’lar da prensibe bağlılık adına önem arz etmektedir.

## Monolith Uygulamalarda Transaction Yönetimi

Monolith mimaride transaction yönetimi Mikroservis Mimariye kıyasla oldukça kolaydır. Bir çok framework veya dil transaction yönetimi için kendi içlerinde bazı api’lar içerirler. (dotnet için **TransactionScope** class’ı gibi) Bu api’lar tüm uygulamanın tek bir veri tabanına sahip olduğu, dolayısıyla tüm transaction’ların tek bir context üzerinde çalıştığı senaryolar için geliştirilmişlerdir. Yani monolith mimarilerde bu api’lar ile basitçe **commit** ve **rollback** işlemlerini yapabiliyoruz.

**Commit** işlemi **scope**’a dahil edilen tüm transaction’lar başarıyla çalıştığında en son yapacağımız işlem iken, **rollback** ise scope’dak herhangi bir transaction’da bir hata oluşması durumunda tüm işlemi iptal etmek için kullanılır.

Transaction scope içerisinde işletilen transactionlar **commit** edilene kadar diske yazılmadan memory’de tutulurlar ve eğer herhangi bir **t** anında **Rollback** yapılırsa, scope içerisinde o ana kadar işletilmiş tüm transactionlar memory’den silinerek işlem iptal edilmiş olur. **Rollback** yapmadan, **Commit** edildiğinde ise diske (veri tabanına) yazılarak transaction başarıyla tamamlanmış olur.

Aşağıdaki ekran alıntısında **TransactionScope** kullanım örneğini görebilirsiniz. Burada söz konusu transaction 2 step’li bir transaction’dır. Örneğin ikinci transaction’da meydana gelecek bir hata **Complete** metodunun çalışmamasına, dolayısıyla birinci işlemin de diske yazılmamasıyla yani iptaliyle sonuçlanacaktır.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F0rhOjLD76gAb6OJMM80B%2F002.png?alt=media&amp;token=1543501f-8b9a-4a80-bb35-66149eb9de98" alt=""><figcaption></figcaption></figure>

## Mikroservis Mimari’de Transaction Yönetimi

Mikroservis Mimari'ler dağıtık mimarilerdir ve dağıtık mimaride bir çok konu için tek ve kolay bir çözüm genelde yoktur. Kimlik doğrulamadan, loglamaya, caching’den integration test yazmaya kadar bir çok konu uzmanlık gerektiren zor konular olarak karşımıza çıkmakta. Transaction yönetimi konusunu da bu konulara dahil ettiğimizi söylememe gerek yok sanırım.

Mikroservis Mimari’lerde yukarıda bahsettiğim ACID prensiplerini korumak kolay bir iş değildir ve birden fazla yol mevcuttur diyebiliriz. Burada yalnızca **2PC** ve **Saga** konularına değineceğiz.

### Two-Phase Commit (2PC) <a href="#id-5d6d" id="id-5d6d"></a>

2PC, dağıtık mimarilerde yukarıda bahsettiğimiz ACID prensipleri korumaya imkan sağlayan bir protokoldür. İsminden de anlaşılacağı üzere 2 fazdan oluşmaktadır ve bu 2 fazı yöneten bir **Kordinatör**’ ümüz mevcuttur. İlk faz **prepare** (hazırlık veya oylama (voting)olarak da geçer, ikinci faz ise **commit** fazı olarak adlandırılır.

Yine e-ticaret örneği üzerinden açıklayalım. Ödeme ve stoktan düşme transaction’larını ele almıştık. Akış başladıktan ve transaction’lar tamamlandıktan sonra **Kordinatör,** hazırlık fazında bu 2 transaction’ın başarılı olup olmadığını yani **commit** işlemi için hazır olup olmadıklarını sorar. Eğer her iki transaction’dan commit için hazırız yanıtını alırsa 2. yani **commit** fazını icra ederek, işlemlerin kalıcı olarak diske yazılmasını sağlar.

Hata senaryosuna gelecek olursak; **Kordinatör**, birinci faz sonunda transaction’lardan **birisinden bile** commit edilemez yani hata oluştu bilgisini alırsa mevcut tüm transaction’ları iptal eder. Böylece işlem bir bütün olarak iptal edilmiş olur.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FpND9nw9kbHhhqCsTkF9f%2F003.png?alt=media&amp;token=af53cd70-803b-4d77-8e57-708c43cc6a32" alt=""><figcaption></figcaption></figure>

### Saga Pattern <a href="#b497" id="b497"></a>

Dağıtık mimarilerde transaction yönetimi için kullanılan yöntemlerden birisi olan **Saga Pattern,** ilk olarak 1987 yılında [**akademik bir makalede**](https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf) ortaya atıldı.

**Saga**, her transaction’ın farklı ve bağımsız bir servis üzerinde lokal olarak çalıştığı ve yine o servis içerisinde verisini güncellediği transaction’lar dizisidir. Bu tasarım kalıbına göre, ilk transaction, dış bir etki ile (kullanıcının kaydet butonuna tıklaması gibi ) tetiklenir ve artık sonraki tüm transaction’lar bir önceki transaction’ın başarılı olması durumunda tetiklenecektir. Transaction’lardan herhangi birisinde meydana gelecek bir hata durumunda ise tüm süreç iptal edilerek **Atomicity** presibine bağlılık sağlanmış olur. Biraz havada kalmış olabilir ancak aşağıdaki örnek senaryo çizimlerimle biraz daha net anlaşılacağını düşünüyorum.

Saga’yı uygulamak için bir kaç farklı yöntem mevcuttur. Ben **Events/Choreography** metodu ile Saga’yı servislerimiz arasında nasıl implemente edeceğimizden bahsedeceğim. Dilerseniz diğer bilindik yöntem olan **Command/Orchestration** metodunu da araştırabilirsiniz.

### **Events/Choreography Yöntemiyle Saga Uygulaması** <a href="#id-7ad5" id="id-7ad5"></a>

Bu yöntemde ilk servis işini icra ettikten sonra bir **event** fırlatır ve bu event’ı dinleyen servis veya servisler tetiklenerek kendi local transaction’larını çalıştırır. Yani her servis aslında bir önceki servisin “ben işimi hallettim sıra sende” demesini bekler. Son servis çalıştıktan sonra artık bir event fırlatmaz ve süreç sonlanır.

**Events/Choreography** yöntem&#x69;**,** Saga’nın prensiplerine en uygun olan yöntemdir. Uygulaması ve yönetmesi nispeten daha  kolaydır. Transaction’lar birbirlerinden tamamen izoledir ve birbirleri hakkında bilgi sahibi olmak zorunda değildirler. Ancak bu yöntemde servislerimizin ve dolayısıyla event’lerimizin sayısı arttıkça sistemin karmaşıklığının da artacağını ve yönetilmesi zor bir hal alabileceğini unutmamak gerekiyo&#x72;**.**

Yine sipariş verme örneğimiz üzerinden başarılı ve başarısız sipariş işlemlerini, iki farklı akış diyagramı üzerinden inceleyelim.

**Örnek Başarılı İşlem Senaryosu (Commit)**

Senaryomuz gayet basit. Hatırlarsanız ilk transaction’ımız harici bir müdahale ile tetikleniyordu. Kullanıcının ekrandan **Satın Al** butonuna tıklamasıyla;

* Saga’mızın ilk transaction’ı yani **Sipariş Servisi** tetiklenir.
* Sipariş servisi **Sipariş Oluşturuldu** Event’ini fırlatır.
* Bu event’i dinleyen **Ödeme Servisi** tetiklenir.
* Ödeme servisi **Ödeme Alındı** Event’i fırlatılır.
* Bu event’i dinleyen **Stok Servisi** tetiklenir.
* Stok servisi **Stoktan Düşüldü** Event’ini fırlatır.
* Bu event’i dinleyen **Bildirim** **ve Sipariş Servisleri** tetiklenir.
* Bildirim servisi kullanıcıya e-mail/sms gönderir.
* Sipariş Servisi siparişin durumunu **Başarıyla Tamamlandı** durumuna günceller.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FbHhqlXQcsf6Bg0Gg9E41%2F004.png?alt=media&amp;token=fc06e868-5fd7-4231-adf0-1e6dcc36b583" alt=""><figcaption></figcaption></figure>

**Örnek Başarısız İşlem Senaryosu (Rollback)**

Kullanıcının ekrandan **Satın Al** butonuna tıklamasıyla;

* Saga’mızın ilk transaction’ı yani **Sipariş Servisi** tetiklenir.
* Sipariş servisi **Sipariş Oluşturuldu** Event’ini fırlatır.
* Bu event’i dinleyen **Ödeme Servisi** tetiklenir.
* Ödeme servisi **Ödeme Alındı** Event’i fırlatılır.
* Bu event’i dinleyen **Stok Servisi** tetiklenir.
* Stok servisi **Ürün Stokta Yok Hata** Event’ini fırlatır.
* Bu event’i dinleyen **Ödeme ve Sipariş Servisleri** tetiklenir.
* Ödeme servisi kullanıcıya para iadesi yapar.
* Sipariş Servisi siparişin durumunu **Başarısız** durumuna günceller.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FKLQbatHeXC0ICRcgjqqa%2F005.png?alt=media&amp;token=54318a46-79fd-48c3-a43b-322016e33621" alt=""><figcaption></figcaption></figure>

**Diyagramları Yorumlayalım**

Öncelikle **Event Fırlatma** ifadesine aşina olmayanlarınız için biraz hava da kalmış olabileceğinden buna değinelim. Diyagramlarda berlittiğim Event’lerin her birisi aslında veri tabanına veya bir message queue’ya atılan bir kayıttan ibaret. Burada veri tabanı mı yoksa mesaj kuyruğu mu olacağı sizin tasarımınıza kalmış. Eğer ciddi yük altında çalışan bir uygulama söz konusuysa RabbitMQ, MsMQ veya Kafka gibi mesaj kuyruk yapıları kullanmanızı öneririm.

Gelelim **Event Dinleme** olayın&#x61;**.** RabbitMQ Message Queue kullanılan bir mimaride açıklayacak olursak. Oluşan her event bir kuyruğa yazılır. Ödeme servisi **Sipariş Oluştu** event’ini dinliyor demek, bu event’in yazıldığı kuyruğa atılan her yeni mesajın Ödeme Servisi tarafından **Subscribe** edilmesi yani tüketilmesi demektir. Her servis için ayrı bir kuyruk olduğunu hayal edin. Hangi event’in hangi kuyruk veya kuyruklara yazılacağını RabbitMq’nun gelişmiş routing yapısıyla kolayca yönetebiliyorsunuz. Başarılı ve başarısız senaryo diagramlarını açıklayalım biraz daha net anlaşılacaktır.

Başarılı senaryo için çok fazla söylenecek bir şey yok aslında. Yalnızca **Stoktan Düşüldü** event’ine dikkatinizi çekmek isterim. Dikkat ederseniz bu event’i dinleyen iki servis var. Sipariş servisi ve bildirim servisimiz. Birkaç cümle önce ‘**kuyruk veya kuyruklara’** ifadesini kullanmıştık yani biz RabbitMQ’ya bir mesaj gönderirken bu mesajı birden fazla kuyruğa yaz diyebiliyoruz.

Gelelim başarısız senaryoya;

Stok servisine kadar her şey yolundaydı, ancak kullanıcının ekranında **Stokta Var** olarak gördüğü ürünün aslında stokta mevcut olmadığı ortaya çıktı ve neticede stok servisi **Stoktan Düşme Hata** event’ini fırlattı. Yani **hata durumunda bir önceki servis için event fırlatılır** diyebiliriz.

Tabi olay bu kadar da basit değil. Örneğin, ödeme servisinin hata alması durumunda sadece ilk servis için event oluşturulması yeterli olacakken, bildirim servisi için farklı bir tasarım yapmak gerekebilir. Neticede bildirim servisi **Saga** akışını bozan, işlemi sekteye uğratan bir servis değil. Yani oluşacak bir hatanın başka bir servis tarafından dinlenmesi gerekmeyebilir. Bildirim servisinde oluşacak hatalar için **retry policy’**&#x6C;er tanımlayabiliriz.

### Saga mı? 2PC mi? <a href="#a770" id="a770"></a>

Açıkçası ben her durumda Saga’yı uygulamayı tercih ederdim. Bunun en önemli nedeni, 2PC nin performans noktasında dezavantaj sağlaması. Hatırlayın, tüm katılımcılardan yanıt gelene kadar kaynakların lock'lı durumda bekletilmesi durumu. Ek olarak, 2PC ile gerçekleştireceğiniz her senaryoyu Saga ile de yapabilirken, tersi her zaman mümkün olmayabilir.

Saga’yı **Long Running Transaction** dediğimiz, transaction’ı birbirinden bağımsız ve asenkron çalışabilen step’lere bölerek yönetmenin doğru olduğu senaryolarda kullanırken, **2PC** nisbeten daha hızlı sonlanan ani transaction’lar için tercih edilebilir.

Saga’da bir sipariş işlemini step’lere (**sipariş-ödeme-stok-email vs..**) bölerek yönetmek kolaylık sağlıyor. Bunun yanında Saga’da her step’ten sonra commit işlemi yapıldığından, yani sonuç dış dünyaya gerçek olarak yansıdığından dolayı (**ödeme adımında müşteriden ödeme alınması gibi**) rollback işlemi daha kritik bir hal alıyor. Ödeme işleminin rollback yapılması yani müşteriye para iadesi yapılması esnasında oluşabilecek bir hata durumunda nasıl aksiyon almamız gerekir? Bu konu belki de Saga’nın en kritik konusu olabilir.


# Veri Tabanı Tasarımı

Mikroservis Mimari’de Veri Tabanı Tasarımı

Diğer bölümlerde olduğu gibi, bu bölümün de **monolith** mimari ile uygulama geliştirenler için de faydalı olacak bilgiler içerdiğini belirterek başlamak isterim.

Gerek Monolith’den Mikroservis’e geçiş sürecinde, gerekse sıfırdan Mikroservis Mimari ile geliştirmeye başlayacağınız projelerinize başlamadan önce üzerinde uzun uzun düşünüp, tartışıp, araştırmalar yapmanız ve cevap aramanız gereken en önemli 3 soru şunlar olacaktır;

* Kaç adet servisimiz olacak?
* ‘**Şu**’ modülü/özelliği ‘**bu’** servisten ayırıp, yeni bir servis mi oluşturmalı yoksa burada mı kalmalı?
* Hangi servis için hangi tip (RDBMS, NoSQL) veri tabanı seçmeli?

Dikkat ederseniz, yazının konusu veri tabanı seçimi olmasına rağmen servisleri nasıl ayrıştırmamız gerektiğinden bahsettik. Çünkü servisleri nasıl ayrıştırdığınız, bir servisin tek bir iş mi (olması gereken), yoksa birden fazla iş mi yapması gibi konular, doğrudan seçeceğiniz veri tabanının tipine etki edecektir. İkinci bölümde örnek bir senaryo üzerinden incelediğimizde nasıl etki ettiğini daha net görmüş olacağız.

Konuyu üç ana bölümde ele alacağız;

* Veri Tabanı Tipleri ve Karşılaştırması
* Mikroservis Mimari’de Doğru Veri Tabanını Seçme
* Yanlış Seçim Yaptığımı Nasıl Anlarım?

## **Veri Tabanı Tipleri** <a href="#id-8145" id="id-8145"></a>

Konu bir seçim yapmaksa eğer, öncelikle alternatiflerimizin ne olduğunu bilmemiz gerekir. Bu alternatifler hakkında ne kadar derinlemesine bilgi sahibi olursak alacağımız kararlarda o kadar doğru olacaktır.

Bu bölümde ilişkisel veri tabanları ve yönetim sistemleri (RDBMS) ile ilişkisel olmayan (NoSQL-Not Only SQL) veri tabanlarından bahsedeceğiz. Her iki tip veri tabanından bahsettikten sonra kısa bir karşılaştırma yapacağız.

### İlişkisel Veri Tabanları ve Yönetim Sistemleri (RDBMS) <a href="#id-9339" id="id-9339"></a>

İlişkisel Veri Tabanları; veriyi diğer verilerle bir ilişki içerisinde tanımlayabilmemize ve erişebilmemize imkan sağlayan veri tabanlarıdır. Bir ilişkisel veri tabanında veri genellikle tablolar halinde tutulur. Tablolar satır ve sütunlardan oluşurlar. Bu tablo/satır/sütun yapısı, ilişkilerin kolay bir şekilde tanımlanabilmesine imkan sağlar.

İlişkisel veri tabanı yönetim sistemleri (**RDBMS**) ise ilişkisel bir veri tabanı oluşturma, güncelleme ve yönetme işlerini yapan yazılımlardır. Çoğu RDBMS veri tabanına erişim ve etkileşim için **SQL** (Structured Query Language) dilini kullanmaktadır.

İlişkisel veri tabanlarında bir tablodaki kayıtlar birbirleriyle ilişkili olduğu gibi tablolar arasında da ilişki olabilir. Bu ilişkiler RDBMS’lerin **veri tutarlılığını** (**data consistency**) sağlamasındaki en önemli etkendir. Tabi burada ilişkilerin sizin tarafınızdan doğru bir şekilde tanımlanmış olması önemlidir.

### **Veri Tutarlılığına Basit Bir Örnek** <a href="#id-46ea" id="id-46ea"></a>

**Musteri** ve **MusteriDetay** isimli iki tablomuz olsun. Bu tablolar arasındaki ilişkiyi doğru olarak kurarsanız, **Musteri** tablosundan bir kayıt silerken size bu kaydın detay tablosundaki bir kayıtla bağlantılı olduğunu ve o kayıt silinmeden silinemeyeceğini söyler.Alternatif olarak, bir müşteriyi sildiğinizde otomatik olarak detay bilgisi de silinmiş olur. Eğer bu ilişkiyi kurmamış olsaydınız, doğrudan **Musteri** tablosundaki bir kaydı silinebilir ve detay tablosundaki karşılığı silinmeden kalabilirdi. Bu kötü senaryonun gerçekleştiğini, yani **MusteriDetay** tablosunda var olan, ancak **Musteri** tablosunda hiçbir karşılığı olmayan detay satırlarının olduğunu düşünelim. İşte bu veri tutarlılığının bozulduğu duruma bir örnektir. Veri tutarlılığı, bu gibi durumların önüne geçilebilmesi için ortaya atılan bir kavramdır ve RDBMS’lerin vaad ettiği en önemli özelliklerindendir.

Bugün piyasaya baktığımızda en popüler ilişkisel veri tabanları olarak, MySQL (ücretsiz), PostgreSQL (ücretsiz), MSSQL, Oracle, IBM DB2 gibi veri tabanlarını sıralayabiliriz. Bu veri tabanlarından hepsi ilişkisel olmasına rağmen, bunlar arasında da yine seçim yaparken bilinçli bir seçim yapmak bizim faydamıza olacaktır.

Örneğin coğrafi bilgi sistemleri (GIS) ile alakalı bir proje geliştiriyorsanız, hiç düşünmeden PostgreSQL kullanmanızı öneririm. PostgreSQL içerdiği GIS spesifik veri tipleri ve eklentileri ( [https://postgis.net](https://postgis.net/) ) ile bu alanda öne çıkmaktadır.

GIS örneğini verme sebebim; Yapacağımız seçimin bir RDBMS / NoSQL seçimden ibaret olmadığını, bunlardan birisinde karar kıldıktan sonra kendi içlerindeki alternatifler arasından da yine doğru tercihi yapmamız gerektiğini vurgulamaktı.

### İlişkisel Olmayan Veri Tabanları (NoSQL) <a href="#id-0d20" id="id-0d20"></a>

İlişkisel veri tabanlarının geçmişi yaklaşık 40 yıl öncesine dayanır. Şüphesiz o zamandan bu zamana ilişkisel veri tabanları gelişim göstermektedir. Ancak yapı itibariyle RDBMS’ler büyük boyutta verilerle başa çıkmak üzere ve bir **cluster** üzerinde dağıtık yapıda çalışmaya pek uygun değillerdir. Büyük miktarda veri ile başa çıkma konusunda cluster üzerinde daha efektif çalışan bir veri depolama teknolojisine olan ihtiyaç günden güne artarken, NoSQL kavramı bu ihtiyaca bir çözüm olarak 1998 yılında ortaya atıldı.

NoSQL camiası, ağırlıklı olarak, yüksek miktarda veri ve yüksek trafiğe odaklandı. **NoSQL, RDBMS’lerin sahip olduğu güçlü ve anlık veri tutarlılığından vereceği taviz ile daha yüksek performans ve erişilebilirlik elde etmeye yöneldi.**

Peki neydi bu **anlık/hızlı veri tutarlılığı**? Önceki bölümde verdiğimiz veri tutarlılığı örneği anlık veri tutarlılığına da bir örnek aynı zamanda. İlişkisel veri tabanlarında anlık veri tutarlılığı (**immediate consistency**) vardır. NoSQL de ise bu anlık, yerini nihai veri tutarlılığına (**eventual consistency**) bırakır. Bu konuyu son bölümdeki **Yüksek Seviye Veri Tutarlılığı** alt başlığında bir gerçek hayat örneği ile ele alacağımız için burada kesiyoruz.

### **CAP Teoremi** <a href="#id-0128" id="id-0128"></a>

NoSQL’in performans ve erişilebilirlik için veri tutarlılığından taviz verdiğinden bahsettik. Taviz vermeden bahsetmişken, CAP teoremine de değinmek gerekiyor. Muhtemelen bir çoğunuzun daha önce bir şekilde denk geldiği düşündüğüm aşağıda görsel, teoremi tek başına açıklıyor aslında. Dikkat ederseniz ortada kırmızı bir çarpı işareti var, yani bu üç özelliğin tamamının bir NoSQL mimari de olamayacağını anlamamız gerekiyor. CAP’ın C,A,P sine birer cümle ile bakalım;

**Consistency**: Dağıtık sistemdeki tüm node’ların aynı veriye sahip olması durumu.

**Availability**: Sisteme yapılan her isteğin başarılı olsun başarısız olsun, bir yanıt alabilmesi durumu. (En güncel veriye sahip olmasa bile.)

**Partition Tolerance**: Mevcut node’lardan bir kısmında network veya başka bir sebepten ötürü bir sorun meydana gelerek erişilmez hale gelse bile, sistemin çalışmasına devam edebilmesidir.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FeutUT56D4MhAyUKSb7qT%2F006.png?alt=media&amp;token=7c05a96b-3cc7-4a4b-861e-27979c40ffc6" alt=""><figcaption></figcaption></figure>

Son olarak NoSQL veri tabanı çeşitlerine ve tercih edildikleri uygulama tiplerine bakacak olursak;

**Document Based** ( MongoDB, CouchDB, etc.) E-ticaret siteleri, İçerik yönetim sistemleri vb.

**Key/Value** ( Redis etc.) Kullanıcı oturum bilgisi saklama, Alış veriş sepeti verisi saklama vb.

**Graph Based** ( Neo4J etc.) Sosyal medya uygulamaları, Graph tabanlı arama uygulamaları vb.

**Column Based** ( Cassandra, HBase etc.) Transaction loglama, IoT uygulamaları vb.

### RDBMS vs NoSQL <a href="#id-6c6c" id="id-6c6c"></a>

İki tür arasındaki farklılıklar çok ta karmaşık ve anlaşılması güç farklılıklar değil aslında. Bütün olay verinin nasıl saklandığı ve nasıl sorgulandığı meselesinden ibaret diyebiliriz. Şimdi alt başlıklar halinde karşılaştırmasını yapalım.

**Ölçeklenebilirlik**

RDBMS’lerinin yatay da ölçeklenebilmesi zor olduğundan, güçlü ve pahalı sunucularla dikeyde ölçeklendirme yoluna gidilir. NoSQL kolayca yatayda ölçeklenebileceğinden sunucu maliyetleri noktasında avantajlı **olabilir**.

Bu arada ölçeklenmenin zorluğundan bahsetmişken, geçenlerde Microsoft’un satın aldığı başarılı yerli girişim **Citus Data’**&#x64;an bahsetmek isterim. Citus Data aslında ilişkisel bir veri tabanı olan PostgreSQL’i dağıtık bir yapıda çalıştırmanıza imkan sağlıyor. Yani siz bir sorgu gönderiyorsunuz ve bu sorgu arka planda birden fazla node üzerinde paralel çalıştırılarak sonuç üretiliyor. Bu da yüksek performans demek tabi.

Açıkçası satın alma haberine kadar Citus Data’yı hiç duymamıştım. Bu teknoloji RDBMS’ler için devrim niteliğinde bir gelişme bana göre. Şöyle de bir blog post’a denk geldim, göz atmakta fayda var.

<https://www.citusdata.com/blog/2018/11/30/why-rdbms-is-the-future-of-distributed-databases/>

**ACID Prensipler**

NoSQL veri tabanlarının ACID olmadıkları yönünde aslında tam da doğru olmayan görüşler var. Önceki bölümde NoSQL veri tabanı tiplerinden bahsettik. Örneğin birçok Graph veri tabanı yapıları gereği ACID’dir. (Neo4J gibi.) Peki ya diğerleri? **CAP** teoreminden bahsetmiştik. NoSQL veri tabanları çoğu zaman **AP** yi seçerek Strong Consistency’den taviz verebiliyorlar. Dikkat ederseniz strong ifadesini kullandım, yani eventual da olsa neticede bir Consistency sağlamış oluyorlar **AP’**&#x79;i seçtikleri zaman.

Dolayısıyla NoSQL veri tabanları ACID uyumlu değildir demek yanlış olacaktır. Kaldı ki ACID, Consistency’den ibaret değildir. ACID prensiplerden daha detaylı bahsettiğimiz transaction yönetimi bölümünü hatırlayınız.

**Bakım Maliyetleri**

RDBMS’lerin bakım maliyetleri yüksektir ve özellikle büyük ölçekli sistemlerde eğitilmiş insan gücüne olan ihtiyaç NoSQL’e göre daha fazladır. Bu da eğer danışmanlık alınıyorsa daha fazla danışmanlık maliyeti anlamına gelmektedir. NoSQL veri tabanları daha az yönetim ve onarım maliyeti getirir. Maliyet konusunda NoSQL veri tabanlarının bir çoğunun open source oluşu da önemli bir etkendir. Lisans ücretleri noktasında RDBMS ile ciddi fark vardır.

**Olgunluk**

RDBMS’ler çok daha eskiye dayandıkları için daha geniş bir topluluğa ve yetişmiş insan gücüne sahip olmakla birlikte oldukça **stabil** çalıştıklarını söylemek yanlış olmaz. Ek olarak hemen hemen tüm RDBMS’ler ortak bir dil olan **SQL** ile veri tanımlaması ve manipülasyonu yaptığından, bu dilde uzmanlaşan birisi için veri tabanları arasında geçiş yapmak kolaydır.

**Big Data Uygulamalarında Kullanım**

Direkt olarak şu tip veri tabanı büyük veri uygulamaları için daha uygundur demek yanlış olmakla birlikte, bazı projelerde her iki tür birlikte kullanılabilmektedir. Veri, öncelikle performans ve ölçeklenebilirlik düşünülerek **unstructured** bir yapıda NoSQL veri tabanına kaydedilir ve asenkron olarak işlenerek **structured** bir yapı halinde ilişkisel veri tabanına yazılır. Ham verinin NoSQL de, işlenmiş olanın ise SQL de tutulması diyebiliriz yani. Böylelikle her iki veri tabanının da en önemli avantajlarından faydalanmış olunur.

**Veri Tutarlılığı (Data Consistency)**

RDBMS yüksek seviye veri tutarlılığı vaat ederken, NoSQL de durum böyle değildir. Önceki bölümde bir örnek vermiştik bu konuya ama bununla yetinmeyeceğiz ve bir sonraki bölümde vereceğimiz sosyal medya uygulaması örneği ile daha net anlaşılacağından eminim.

**Şema Bağımlılığı**

NoSQL şema bağımsız olduğundan veri formatı uygulamaya çok fazla dokunmadan da değiştirilebilir. RDBMS’ler de **change management** büyük bir sorun haline gelebiliyor, özellikle kötü tasarlanmış ve ilişkileri doğru olarak kurulmamış veri tabanları için.

Sonuç olarak; RDBMS’ler NoSQL veri tabanlarından iyidir veya tam tersi doğrudur gibi söylemler kesinlikle yanlıştır. Her ikisinin de diğerine göre daha avantajlı olduğu senaryolar mevcuttur. Burada bize düşen hangi durumda hangisinin daha avantajlı olduğunu bilmek ve doğru seçimi yapabilmektir.

## Mikroservis Mimari’de Doğru Veri Tabanını Seçme <a href="#id-7e0d" id="id-7e0d"></a>

Bildiğiniz üzere Mikroservis Mimari’yi uygulamak sizi bir programlama diline, framework’e, veri tabanına vs. bağlı kalmaktan kurtarıyor. Her bir servisinizi farklı farklı diller ve platformlarda bağımsız olarak geliştirerek yine bağımsız olarak canlıya alabiliyorsunuz. Tabi mimarinin temel prensiplerine sadık kalırsanız.

Bu dil, framework ve veri tabanı bağımsızlığı konusunda en çok göz ardı edilen konu veri tabanı konusu olabilir. Özellikle monolith’den Mikroservis’e geçişlerde, mevcut veri tabanı servisler özelinde parçalanırken, her Mikroservis için mevcut monolith veri tabanı ile aynı veri tabanını kullanmak ilk seçenek oluyor ve genelde de böyle ilerleniyor.En azından gözlemlerim ve okuduklarım kadarıyla durum böyle. Konfor alanımızdan çıkmak istemeyişimiz aklıma gelen ilk sebeplerden. Bunun bir neticesi olarak ilk hatayı yapmak kaçınılmaz oluyor. Şöyle ki;

> **Servislerimizi seçtiğimiz veri tabanının türüne göre ayrıştırmaya başlıyoruz. Aslında yapmamız gereken bunun tam tersi olmalı. Servislerimizi veri tabanından bağımsız düşünerek, atomik ve en doğru şekilde tasarlayıp, veri tabanını ilgili servisin yapısına göre seçmeliyiz.**

İyi güzel de hangi kriterleri baz alarak seçim yapmamız gerekiyor diye düşünebilirsiniz. Bizim için en önemli iki parametre, yüksek veri tutarlılığı ve yatayda ölçeklenebilme konularıdır.

### **Yüksek Seviye Veri Tutarlılığı ve Ölçeklenebilme Gereksinimi** <a href="#dbb7" id="dbb7"></a>

Servisiniz için yüksek seviye **Consistency** önemliyse RDBMS kaçınılmazken, aksi durumda daha iyi performans için NoSQL tercih edebilirsiniz. NoSQL de **immediate consistency** yerine **eventual consistency** olduğunu söylemiştik.

Biraz açmak gerekirse; Örneğin bir sosyal medya uygulamanız var ve veri tabanı olarak NoSQL’i tercih ettiniz. (doğru tercih)

Trafiğiniz çok olduğundan dolayı servislerinizi bir çok node (sunucu) üzerinde sunuyor, yatayda ölçekleniyorsunuz. Sosyal medya uygulamalarında paylaşılan içeriklere yapılan yorumlar veya beğeni sayılarının, tüm **node**’lar da herhangi bir **t** anında aynı değere sahip **olmaması** büyük bir sorun teşkil etmez. Şöyle ki;

Türkiye’de ki bir kullanıcı, bir paylaşımdaki beğeni sayısını 500 olarak görürken aynı anda aynı paylaşıma bakan Rusya’da ki kullanıcı bunu 495 olarak görebilir. Burada **Eventual Consistency** bir süre sonra sağlanacak ve tüm node’lar da aynı beğeni sayısı tutuluyor olacaktır. Biz bu gibi durumların oluşma ihtimalini bilerek, performans ve yüksek ölçeklenebilirlik için NoSQL tercihinde bulunduk ve doğru olanı yaptık.

**Immediate Consistecy** için ise finansal uygulamaları örnek gösterebiliriz. Parasal işlemler söz konusu olduğu için ilişkisel veri tabanlarının daha kararlı **ACID** özelliği önem kazandığından, genelde RDBMS’ler tercih edilmekte.

### Örnek Senaryo <a href="#f9a1" id="f9a1"></a>

Hatırlarsanız, servislerinizin yüklendikleri sorumluluğun boyutlarının doğrudan veri tabanı seçiminiz üzerinde etkisi olduğundan bahsetmiştik. Örnek bir senaryo üzerinden ne demek istediğimize geçmeden önce bir kaç kelam etmekte fayda var.

İdeal Dünya’da bir Mikroservis’in yalnızca tek bir işi yapması ve o işi en iyi şekilde yapması istenir. **SOLID** prensiplerin ilki olan **Single Responsibility** prensibini bilirsiniz, sınıfları ve metotları mümkün olduğunda atomik tutarak onlara tek bir sorumluluk yüklemeye yöneltir bizi. Mikroservis Mimari’de servisleri tasarlarken bu prensibe bağlı kalmalıyız.

Servisimiz ne kadar büyür ve yaptığı iş ne kadar karmaşıklaşırsa, RDBMS kullanımı mecburiyet haline gelebilir. O zaman biz de ilişkisel veri tabanı kullanırız diye düşünebilirsiniz. Bu durumda RDBMS ile gelen **JOIN** işlemleri sizi bekliyor demektir. JOIN’leme işlemi  maliyetli bir işlemdir esasında. JOIN’lenen tabloların içerdiği veri miktarı arttıkça performansınız yerlerde sürünecektir, öyle ki index’ler bile sizi kurtaramayabilir.

Şimdi, servisleri **mümkün olduğunca** atomik tasarlayarak, NoSQL kullanmak mı? Yoksa ayırabileceğiniz servisleri ayırmayarak RDBMS kullanmak mı? Karar sizin. Bu arada konuyla ilgili Martin Fowler'ın [**buradaki**](https://martinfowler.com/articles/microservices.html#DecentralizedDataManagement) yazısına da göz atmanızı tavsiye ederi&#x6D;**.**

Gelelim örnek senaryomuza. Öncelikle hatalı bir tasarım ile veri tabanı seçimlerini yapacağız. Ardından daha doğrusu nasıl olur sorusunu sorarak, problemli noktaları saptayıp daha doğru bir tasarıma geçeceğiz.

> **Ön Not:** NoSQL / RDBMS seçimini yapmadan önce her servisin yalnızca kendisinin doğrudan erişebildiği izole bir veri tabanı olması gerektiğini bilmelisiniz. Bu izole veri tabanları aynı sunucu üzerinde olabileceği gibi farklı sunucular üzerinde de yer alabilir. Bir servis başka bir servisin verisine ihtiyaç duyuyorsa bu ihtiyacını o servisin veri tabanına doğrudan erişerek **gideremez.** En doğrusu bir **event-bus** üzerinden **full asenkron** bir haberleşme yapılmasıdır. Eğer bu yapılamıyorsa, servisler bir birlerine anlık olarak **http request** yapabilir. Bu anlık http istekleri, servisleri birbirine bağımlı kıldığı için çok doğru bir yöntem değildir ama başka bir servisin veri tabanına direkt erişmek kadar da hayati bir hata değildir en azından.

### **Uygulama** <a href="#id-8649" id="id-8649"></a>

Bir çok alt firması olan bir holding için ilişkisel veri tabanı kullanan monolith yapıda bir insan kaynakları uygulamamız olsun. Bu uygulamanın bir kullanıcı girişi bir de admin panel tarafı var.

Kullanıcılar sisteme giriş yaparak kişisel bilgilerini girme, izin talep etme, masraf fişi gönderme gibi işlemleri yapabildiği gibi, kalan izin gibi bilgilerini de **read-only** olarak görüntüleye biliyorlar. Sistem adminleri ise, yeni kullanıcı, yeni departman ve yeni firma ekleme gibi işlemleri yönetim panelinden yapabiliyorlar.

Mikroservis mimariye geçiş için yazının girişinde sorduğumuz 3 soruyu sorarak başlıyoruz ve neticede aşağıdaki yanlış tasarımı yaptığımızı düşünelim. (Doğru tasarıma bakmadan yanlışlığın nerede olabileceğini tahmin edebilirsiniz.)

> **Not:** Bu örnek uygulamanın, işlevi ve kullanıcı sayısı göz önüne alındığında, büyük miktarda veri ve ölçeklenme gibi problemleri olmayacağı aşikardır. Dolayısıyla hatalı tasarım diye belirttiğimiz yapıda kalmasında bir mahsur olmayabilir. Siz bu hatalı ve doğru tasarımların , büyük ölçekli ve yüksek trafikli bir uygulamada yapıldığını hayal edebilirsiniz.

### **Hatalı Mimari** <a href="#id-3c6f" id="id-3c6f"></a>

Monolith uygulamamız MySQL veri tabanına sahip olduğu için Mikroservis Mimari'ye dönüşüm sonrasında tüm servislerimiz için yine MySQL ile devam etmek istedik.&#x20;

Toplamda 6 adet servisimiz olsun dedik. Bunlardan 5 tanesinin kendisine ait izole bir veri tabanı var. Aşağıdaki gibi çizmeye çalıştım;

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FtH1iYFrUOZR02og7gfWO%2F007.png?alt=media&amp;token=3be46b01-0231-4545-8a43-e581af9b1cdb" alt=""><figcaption></figcaption></figure>

### **İyileştirilmiş Mimari** <a href="#id-6f44" id="id-6f44"></a>

Geliştirmeler ve testler esnasında fark ettik ki, User, Company ve Department servisleri bir birlerine çok fazla http isteği yapıyorlar, yani bağımlılık oranları bir hayli yüksek. Bu durum kullanıcı sayısı arttıkça daha büyük bir sorun haline gelecek gibi duruyor.

Dolayısıyla bu 3 servisi birleştiriyoruz ve yine ilişkisel bir veri tabanı olan MySQL ile devam ediyoruz. Expense (masraf) ve Annual Leave (izin) servisleri ise bağımsız kalmaya devam ediyorlar. Ancak ilişkisel bir veri tabanı kullanmamızı gerektiren bir durum olmadığını düşünerek, MongoDB ile yola devam diyoruz. Mimarinin son hali kabaca şöyle şekilleniyor;

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FbiUr8qVTMjlLRBuIXSqQ%2F008.png?alt=media&amp;token=96ebf23e-c029-4f99-9755-8f7e01d8972a" alt=""><figcaption></figcaption></figure>

**Ne Yaptık?**

Servis sayımızı azaltarak, 2 servislik bir DevOps yükünden kurtulmuş olduk. Bununla kalmadı tabi, bir birleri arasında çok yoğun bir http trafiği oluşturan 3 servisin meydana getirdiği bu trafiği de bitirmiş olduk. Eğer MySQL yerine ücretli olan MsSQL gibi ücretli bir veri tabanı kullanmış olsaydık ki özellikle ülkemizde çok yaygın bir kullanıma sahip, bu lisans ücretinden de tasarrufa gitmiş olacaktık.

**Daha İyisi Olamaz mı?**

Her zaman olur. Burada dikkat ettiyseniz servisler bir birlerine doğrudan http call ile erişmekte. Full asenkron ve daha gevşek bağlı bir tasarım için RabbitMQ gibi bir message broker kullanmamız gerekir. Bir önceki, servisler arası iletişim bölümünde detaylı olarak bahsetmiştik hatırlarsanız.

## Yanlış Bir Seçim Yaptığımı Nasıl Anlarım? <a href="#e77d" id="e77d"></a>

Her iki tip veri tabanı içinde kısaca ip ucu vermek gerekirse;

Örneğin, Doküman tabanlı NoSQL veri tabanı kullandığınız bir servisiniz de, transaction kullanımına ihtiyaç duyuyorsanız, aynı anda birden fazla dokümanı güncelleme gibi bir ihtiyacınız oluyorsa, NoSQL’in kapsama alanından çıkmış, ilişkisel veri tabanı Dünyasına girmişsiniz demektir.

Benzer şekilde, ilişkisel veri tabanı kullandığınız servisiniz de, tabloları JOIN leme, transaction gibi özellikleri hiç kullanmıyorsanız ve büyük miktarda veri söz konusuysa ki bu durumda yatayda ölçeklenme kaçınılmazdır, o halde NoSQL kullanmak daha doğru bir tercih olacaktır.

Son olarak;

NoSQL veri tabanlarını RDBMS’lere ucuz bir alternatif olarak düşünerek kullanmak hata olur. Ne olduklarını ve hangi yaraya merhem olduklarını bilerek, bilinçli bir seçim yapmak zorundayız.


# Servisler Arası İletişim

Mikroservis Mimari’de Servisler Arası İletişim Yöntemleri

Bu bölümde, “Servisler arasındaki haberleşmeyi nasıl sağlamalıyız?” sorusuna aşağıdaki 3 başlık altında yanıt arayacağız.

* Request-Driven Mimari
* Event-Driven Mimari
* Hybrid Mimari

## Request-Driven Mimari <a href="#a4ed" id="a4ed"></a>

Servis sayımız arttıkça mimarimizin karmaşıklığı da, http trafiğimiz de doğru orantılı olarak artacaktır. Bir Mikroservis , verisine ihtiyaç duyduğu başka bir servise, bir http client üzerinden istekte bulunur ve bu işlem bir **IO** (Thread Blocking IO) işlemi olduğu için aslında maliyetli de bir işlemdir. Servisler (sunucular) client’larıyla olan bu iletişimi **socket**’ler üzerinden yaparlar ve bu socket’ler sonsuz sayıda değildir, bu yüzden socket kullanımı iyi yönetilmesi gereken bir konudur.

Dolayısıyla mimarimizi tasarlarken servislerimizin kendi aralarında yaptıkları isteklerin sayısı konusunda biraz cimri davranmamız gerekiyor. Tabi bunu yaparken, aslında ayrıştırılması gereken servisleri sırf http istek sayısını azaltacağız diyerek birleştirmek de yanlış olacaktır. Aşağı tükürsek sakal yukarı tükürsek bıyık durumu yani. Mikroservis  Mimari’nin zorluklarının üstesinden gelmek de bu gibi kararları doğru verebilmekten geçiyor zaten.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FgO5j45v7PMJ7RvCun46U%2F009.png?alt=media&amp;token=10feb03b-5465-40ea-827f-7baf4d595c31" alt=""><figcaption></figcaption></figure>

Bu mimari de adından da anlaşılacağı üzere bir service, verisine ihtiyaç duyduğu bir diğer servise doğrudan istekte bulunur. Servislerimizin modern **Rest** servisleri olduğunu kabul edersek yapılan istekler, **GET, POST, DELETE ve UPDATE** isteklerinden ibaret olacaktır.

Yukarıdaki çizimde **fire-and-forget** iletişim şeklini de göstermiş olmak adına, sarı renkli olan servisten geri dönüş belirtmedim. Elbette her http request’in bir http response’u olacaktır, burada isteği yapan kırmızı ve yeşil servislerin dönen resonse ile ilgilenmediklerini anlıyoruz. Örneğin bu sarı renkli servisimiz notifikasyon veya log servisimiz olabilir. (Loglama işlemini http servis üzerinden yapmak **genelde** yanlış bir tercih olur)

Request-Driven Mimari’de servislerimiz arasındaki iletişimi iki yolla sağlayabiliriz;

### Senkron (Synchronous) İletişim <a href="#id-1840" id="id-1840"></a>

Http protokolü senkron çalışan bir protokoldür. Client bir istek yapar ve sunucudan yanıt dönmesini bekler. Client tarafında servis çağrısını yapan kodun senkron (thread’in blocklanması durumu) veya asenkron (thread’in bloklanmaması ve yanıtın **call back** ile gelmesi) yazılması Http’nin senkron bir protokol olduğu gerçeğini değiştirmez.

Burada aslında ilginç bir durum söz konusudur. Client’in servis çağrısını asenkron olarak yapması(**call back** yapısı ile) veya sunucunun yanıtı asenkron olarak dönmesiyle aslında bir anlamda senkron bir protokol olan Http’den asenkron yanıt vermiş/almış oluyoruz Ancak bu Http protokolünü değiştirdiğimiz onu asenkron bir şekilde çalıştırdığımız anlamına gelmiyor elbette.

Buna örnek olarak .Net Framework 4.5 ile gelen **async/await** yapısını verebiliriz. Bu yapı, asenkron istek yapma veya yanıt dönme işlemlerini çok kolay bir şekilde yapmamıza imkan sağlıyor. Dolayısıyla Mikroservis'lerinizi geliştirdiğiniz framework’ün ve dilin buna benzer bir yapıya sahip olması, yani isteklerinizi ve yanıtlarınızı asenkron olarak yapmanıza imkan sağlaması önem arz ediyor.

DotNet’in yanı sıra diğer popüler framework’lerin (java, php, nodejs, ruby, go vs.) hepsi benzer bir call back yapısına sahip midir, yüksek ihtimalle evet. Ancak dotnet’in **async/await** yapısının kodu sadeleştirdiği kadar sadeleştirebilirler mi emin değilim açıkçası. Burada biraz dotnet güzellemesi yapmış olduk ama bana göre **async/await** yapısı bunu fazlasıyla hak ediyor.

### Asenkron (Asynchronous) İletişim <a href="#id-74d1" id="id-74d1"></a>

Http’nin senkron çalıştığından ve call back mekanizmalarıyla bir şekilde client veya sunucu tarafında bir **asenkronizasyon** elde ettiğimizden bahsettik.

Servisler arası iletişim için Http haricinde kullanabileceğimiz, üstelik asenkron bir protocol olan **AMQP’**&#x64;en (Advanced Message Queuing Protocol) kısaca bahsedelim.

Wikipedia tanımı;

> The **Advanced Message Queuing Protocol** (**AMQP**) is an open standard application layer protocol for message-oriented middleware.

**AMQP**’nin en önemli özelliklerini, mesaj yönlendirme, kuyruklama, routing (p2p ve pub/sub), dayanıklılık (güvenilirlik) ve güvenlik olarak sıralayabiliriz. AMQP, çok farklı yapıda ve birbirinden bağımsız çalışan sistemler arası iletişimi kolaylaştırdığı için, sistemlerin birlikte çalışabilirlik (**interoperability**) yönlerini güçlendirmemize de olanak sağlıyor.

**AMQP**’nin reliability (güvenilirlik) özelliğine ayrı bir parantez açmak gerekiyor. AMQP bu özelliğini, içerdiği 3 farklı teslimat garanti (**delivery guarantees**) modu ile kazanmıştır. Kısaca açıklamak gerekirse;

* **at-most-once :** Publisher mesajı **en fazla** 1 kere gönderir ve bu yöntemde mesajın kaçırılma riski vardır çünkü consumer’dan mesajı aldığına dair bir teyit beklenmez. RabbitMQ ve Kafka destekler.
* **at-least-once :** Publisher mesajı **en az** 1 kere gönderir ve bu yöntemde mesajın tekrarlı (duplicate) gönderilme riski vardır çünkü consumer’dan teyit alınırken bir hata meydana gelebilir. RabbitMQ ve Kafka destekler.
* **exactly-once :** Publisher’ın mesajı bir veya yalnız bir kere göndermiş olmasını garanti eder. Diğer iki yöntem kadar yaygın değildir. Daha spesifik, yani kısıtlı senaryolar için kullanışlı olabilir. Yalnızca Kafka destekler.&#x20;

RabitMQ ile Kafka 'yı detaylı bir karşılaştırma yapmışlar [detaylar burada.](https://jack-vanlightly.com/blog/2017/12/4/rabbitmq-vs-kafka-part-1-messaging-topologies)

Sisteminizin bu 3 yöntemden hangisini tolere edeceğine siz karar vererek uygun konfigürasyonu yapmalısınız. Örneğin, işlemleriniz **idempotent** yapıdaysa ve dolayısıyla bir mesajın kuyruktan 2 kere alınıp işlenmesi durumu sizin için sorun teşkil etmiyorsa **at-least-onc**e modunu seçebilirsiniz.

RabbitMQ, **AMQP**’yi destekleyen modern message broker’lara baktığımızda ilk aklımıza gelenlerden. Öyle ki, AMQP hakkında araştırma yaptıysanız karşınıza sürekli RabbitMQ’nün çıktığını görmüşsünüzdür. RabbitMQ hali hazırda MQTT, STOMP, AMQP gibi bir çok mesajlaşma protocol’ünü desteklemektedir. Sonraki bölümlerde RabbitMQ’den biraz daha bahsedeceğiz.

## Event-Driven Mimari <a href="#id-42b2" id="id-42b2"></a>

Mikroservis Mimari dünyasında en zor konulardan birisi data bütünlüğünün sağlanması ve herhangi bir **t** anında tüm data’mızın anlamlı yani beklenen bir **state’**&#x64;e olmasının garanti edilmesi konusudur. Buna transaction bütünlüğünün sağlanması da diyebiliriz. Monolith mimariye göre kıyas götürmeyecek kadar zorlu bir süreç olduğu herkesin malumu.

Bir önceki transaction yönetimi bölümünde bu konuyu daha detaylı olarak incelemiştik, burada ise transaction yönetimi konusunun bizi **event-driven** mimariye götüren yanlarına değineceğiz.

### Event Derken? <a href="#id-560b" id="id-560b"></a>

Bu mimari’de event ile kastettiğimiz şey, bir servisin kendi domain’inde bir kaynağın durumunu değiştirmesiyle birlikte bu değişiklik bilgisini ilgili servis veya servislerle paylaşmasıdır. Bu paylaşımı da genelde bir mesaj kuyruk yapısı üzerinden yapar. Sürekli duyduğumuz **event fırlatma** tabirinin bu mimaride ki karşılığı “<mark style="background-color:green;">ben şu değişikliği yaptım, onu da şu kuyruğa veya kuyruklara yazdım ilgililere duyurulur</mark>” demektir.

Event-Driven mimariye hiçte yabancı değiliz aslında, gündelik hayatımız da bile bazı örnek senaryolar mevcut. Örneğin; canınız hamburger çekti ve soluğu bir hamburgercide aldınız ve sipariş için sizi ilk karşılayan görevliyle konuşuyorsunuz, siparişinizin detayını verdiniz ve beklemeye başladınız.

Siparişiniz hazır olana dek mecburen bekleyeceksiniz. Peki siparişinizi alan görevli? Sizinle beraber boş boş bekleyip, siz siparişinizi teslim aldıktan sonra sıradaki müşteriyle ilgilense nasıl olurdu? Elbette saçma olurdu, ancak **senkron** çalışan **request-driven** mimaride olan şey tam da bu.&#x20;

Ama biz asenkron iletişim istiyoruz, kaynaklarımızı daha verimli kullanmak ve daha iyi performans için buna ihtiyacımız var. Devam edelim.

Siparişi sizden alan görevli bunu siparişi hazırlayacak olan kişiye iletir. (**order\_created event’i**) Ardından sıradaki müşteriyle ilgilenirken, siz boş bir masa bulup alarmın sizin için çalmasını beklersiniz. Siparişiniz bitince ilgili çalışan “x nolu sipariş hazır” bilgisini verir, (**order\_ready event’i**) ve sıradaki siparişi hazırlamaya başlar. **Order\_ready** event’inin muhatabı olan çalışan size siparişinizin hazır olduğunu bildirir ve siz gider teslim alırsınız. (**order\_delivered event’i**) Çok uzatmamak adına bazı detayları atlamakla birlikte, gündelik hayattan basit bir **event-driven** süreç örneği vermiş olduk aslında.

Aşağıdaki örnek çizimde 4 adet Mikroservis ve bir mesaj kuyruğumuz mevcut. Buradaki okların tamamı iki yönlü olmak zorunda değildi. İki yönlü olması, o servisin aslında hem bir **producer** yani event oluşturan, hem de bir **consumer** yani event dinleyen (tüketen) olduğunu gösteriyor bize. Bir servis sadece producer, sadece consumer veya her ikisi de olabilir üstlendiği göreve göre.

Örneğin; örnek senaryomuzda hamburgeri hazırlayıp diğer görevliye teslim eden görevli, **order\_created event**’ini dinleyerek, **order\_ready event**’ini oluşturduğu için iki yönlü bir servistir diyebiliriz.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FjWLahO0eWMFMoWiiKkai%2F010.png?alt=media&amp;token=c8de09b3-9e50-40ef-85f9-a26e3f5af69c" alt=""><figcaption></figcaption></figure>

Event-Driven mimarinin avantajları olarak şunları sayabiliriz;

* Gevşek-Bağlı(loosely coupled) bir mimari oluşturmamıza olanak sağlar.
* Gevşek bağlılık servislerin **development** eforunu azaltır.
* İletişimimiz asenkron olacağı için performans kazanımı sağlar.
* Yatayda kolay ölçeklenebilirlik (scalability) sağlar.
* Mesaj kuyruğu sayesinde, consumer servis bir sebepten ötürü erişilemez durumdayken veri kuyrukta kalır ve tekrar erişilebilir olunca data kaybı yaşamadan kuyruğu tüketmeye devam eder. (Sonraki bölümde bahsedeceğimiz notifikasyon servis örneği)

## Hybrid Mimari <a href="#e216" id="e216"></a>

Bu mimari adından da anlaşılacağı üzere bahsettiğimiz iki mimarinin birlikte kullanıldığı yapıları ifade eder. Eğer tamamen event-driven mimari ile kurulan bir sisteme sahipseniz veya en azından aşinalığınız varsa, “hybrid yapıya ne zaman ihtiyaç duyulur ki” diye düşünebilirsiniz. İlk bakışta gerçek hayat örneklendirmesi yapamayabilirsiniz doğal olarak. Neticede event-driven yaklaşım, request-driven kadar yaygın değil. En azından benim gördüğüm kadarıyla öyle. Bu yüzden genelde, request-driven ile inşa edilen sistemlere ihtiyaca göre bir **event-bus** sonradan entegre edilebiliyor.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fq2vyq1Tj7AMCiKJ74d73%2F011.png?alt=media&amp;token=85302f12-618b-43e3-b325-ee39e0822962" alt=""><figcaption></figcaption></figure>

Bir gerçek hayat örneği verecek olursak;

Request-Driven mimariyle kurgulanmış Mikroservis’leriniz var. Uygulamanıza notifikasyon gönderme özelliğini ekleyeceksiniz. Çeşitli servisler kendi domain’lerinin gerektirdiği şekilde kullanıcılara doğrudan bazı notifikasyonlar göndermeliler. Hemen Notification Service adında yeni bir Mikroservis oluşturdunuz ve request-driven yapınıza entegre ettiniz. Bu şekilde devam edebilirsiniz elbette.

Peki burada notification service kendisine gelen notifikasyon gönderim isteklerini bir kuyruktan okuyamaz mı? Diğer servisler RabbitMQ, Kafka gibi bir kuyruk yapısı üzerinden mesajları notification service’in dinlediği bi kuyruğa gönderebilir ve işlerine devam ederler. **Fire-and-Forget** dediğimiz iletişim şekli yani. Notification service ise notifikasyon isteklerini gönderen servislerle doğrudan iletişim içerisinde değildir artık ve isteğin kimden geldiğini de bilmek zorunda değildir. Artık tek yapması gereken bir kuyruğu dinlemek ve gelen datayı alarak notifikasyon gönderme işini icra etmektir.

Bu şekilde tasarlayarak bağımlılıklarımızı azaltmış olduk. Bir diğer avantajı ise, notification service’imiz bir sebepten ötürü erişilemez hale gelirse, iletişimi asenkron hale getirdiğimiz için servis tekrardan erişilebilir olduktan sonra kuyrukta birikmiş olan veriyi alarak notifikasyonları eksiksiz olarak göndermeye devam edecektir. Aynı senaryoda Request-Driven mimaride eğer bir **retry-policy** uygulamadıysak notifikasyonları kaybetmiş olacaktık ki, **retry-policy** uygulamamıza rağmen kaybetme ihtimali yine olabilir.

Bir sonraki bölümde servislerimizin bir birlerine yaptıkları http isteklerinden tamamen kurtularak, daha bağımsız servisler elde edebilmemize imkan sağlayan bir pattern'dan ve Domain-Driven Design'dan bahsedeceğiz.


# DDD ve Mikroservis Mimari

Domain Driven Design'ın Bounded Context Kavramı ve Mikroservis Mimari

Bir önceki bölümde  bahsettiğimiz iletişim yöntemlerinden olan asenkron iletişimde event-based mimari uygulansa bile servisler veri paylaşımı için birbirlerine anlık olarak http istekleri attıkları için "bağımsızlık" prensibine aykırı bir durum oluştuğundan kısaca bahsetmiştik. Bu bölümde bu http isteklerinden de kurtularak daha izole ve bağımsız servislere nasıl ulaşırız sorusunun yanıtını arayacağız.

Konuyu aşağıdaki alt başlıklarda ele alarak anlatmaya çalışacağım. Bu bölümde esas değinmek istediğim konu son madde, yani veri paylaşımı konusu. Bu önemli konuyu örnek bir senaryo üzerinden inceleyeceğiz. Önceki bölümleri bir ön hazırlık olması açısından eklemenin iyi olacağını düşündüm.

* Mikroservis Mimari ve Domain-Driven Design
* Bounded Context nedir?
* Her Bounded Context bir Mikroservis anlamına gelir mi?
* **Bounded Context’ler (Mikroservis’ler) arası veri paylaşımı**

## **Mikroservis Mimari & DDD**

Mikroservis Mimari ve DDD gibi iki ağır konuyu bir başlık altına sığdırmaya çalışmayacağız elbette, ki biraz iddialı bir hedef olurdu bu.

Bu bölümde, bu iki mimari arasındaki ilişkiyi birlikte kullanılabilirlik yönünden inceleyemeye çalışacağız.

* **Birlikte Kullanmaktan Kastımız Nedir?**

Ekip olarak yeni ve uzun soluklu bir projeye başlıyorsunuz ve proje belirli bir olgunluk seviyesine ulaştıktan sonra monolith den Mikroservis mimariye dönüştürmeyi planlıyorsunuz diyelim. Hedefte kesin olarak Mikroservis mimari olmasına rağmen, başlarken monolith yapıda başlayarak devam ediyorsunuz ki bence de böyle yapmalısınız. ( Monolith mi yoksa Mikroservis mi başlamanın daha doğru olduğu sorusu bu yazsının konusu olmadığından burada üzerinde durmadan devam edelim. )

Monolith yapınızı kurgularken aldığınız teknik kararların, ileride Mikroservis Mimari’ye dönüşüm sürecinizin zorluk seviyesini belirleyeceğini unutmamalısınız. Tam bu noktada DDD’den bahsedebiliriz. Monolith yapıda başladığımız projede DDD’yi prensiplerine sadık kalarak doğru bir şekilde uygularsanız, bu dönüşüm işlemini hem daha kolay hem de daha doğru ve daha az taviz vererek yapabilirsiniz. Bu avantajı bize sağlayacak olan ve bir sonraki bölümde bahsedeceğimiz kavram DDD’nin Bounded Context kavramı.

Bu arada, monolith mimarinizde DDD uygulamazsanız Mikroservis Mimari dönüşümü yapılamaz gibi bir mesaj vermeye çalışmıyorum. Amacımız gevşek bağlı bir mimari oluşturmak ve DDD’nin de burada bize yardımcı olabileceğinden bahsediyorum aslında. Yani DDD buradaki tek alternatifimizi değil elbette.

Mesela, son zamanlarda adını biraz daha fazla duymaya başladığım **Modular Monolith** tasarımdan da çok kısa bahsetmek isterim. Aslında bu mimari için ismiyle müsemma demek yanlış olmayacaktır. Aşina olduğumuz monolith mimarinin modüler, yani bağımlılıklardan mümkün olduğunca arındırılmış bir tarzda kurgulanması diyebiliriz. Konuyla ilgili [**burada**](http://www.kamilgrzybek.com/design/modular-monolith-primer/) güzel bir makale mevcut bir göz atmanızı tavsiye ederim. Yine aynı makale yazarının, DDD ve Moduler Monolith mimariyi birlikte uygulayarak geliştirdiği, incelemeye değer gördüğüm bir projeye de [**buradan**](https://github.com/kgrzybek/modular-monolith-with-ddd) ulaşabilirsiniz.

## **Bounded Context Nedir?**

Bounded Context, DDD’nin anlaşılması biraz zaman alan ve aynı zamanda da en önemli kavramlarından birisidir. Burada “zor” ile kastettiğim şey; **Bir Bounded Context’in sınırlarının belirlenmesi** konusu. Aynı zorluk bir **Aggregate**’in tanımlanması için de geçerli diyebilirim.

Domain’im de kaç tane Bounded Context olduğu, bunların sınırları ve birbirleriyle hangi noktalarda ilişkili oldukları konuları kritik önem arz ediyor.

* **Bounded Context’leri Keşfedilmesi**

Bounded Context’leri domain expert’ler ile konuşarak ve bazı ip uçlarından faydalanarak ortaya çıkarmalıyız. Bu ip uçlarına gelmeden önce belirtmekte fayda var; Bounded Context leri bir kere belirledim, artık değişmez gibi bir düşünceye kapılmamalıyız. Domain expert’lerle konuşarak ve değişen şartları da göz önüne alarak çizdiğiniz sınırlarda değişiklikler yapmanız, Bounded Context’lerinizi yeniden şekillendirmeniz gerekecektir.

( Hatta belki bu sınırlar belirginleşene kadar DDD’yi bir kenara bırakmalı ve Bounded Context’lerinizi büyük ölçüde netleştirdikten sonra uygulamanızı DDD için refactor etmelisiniz. Ancak bu refactoring sürecinin maliyeti sizin bu süreci başlatma zamanınıza göre belirleneceği için elinizi çabuk tutmanız gerekebilir. )

Bir Bounded Context’in sınırlarını belirlerken domain expert’ler ile doğrudan konuşma dışında hangi ip uçlarından faydalanabiliriz biraz bunlara değinelim.

Kullanıldığı domain’e göre farklı anlamlara gelebilen kavramları bulmaya çalışın. Örneğin ‘x’ kelimesi kullanıldığı yere göre 2 farklı anlama bürünüyorsa, bu 2 farklı Bounded Context’in varlığını işaret ediyor **olabilir**. Örneğin; **Product** kelimesi, **Shipment Context**’in de ağırlığı olan taşınacak bir **yük** anlamına gelirken, **Inventory Context**’in de elde kaç adet bulunduğu veya mevcut olup olmadığı önemli olan bir **sayı**dan ibaret aslında.

Diğer bir ip ucu olarak; Bounded Context’lerinizi tanımladınız ve geliştirme süreciniz devam ediyor diyelim. Ancak bir sorun var, bir context’de ki bir veriyi değiştirdiğinizde başka bir context’te de bir veri değiştirmek zorunda kalıyorsunuz. Bu iki context’in birbirine bağımlı olduğu anlamına geliyor. Daha da kötüsü bu durum farklı farklı veriler için sıkça yaşanmaya başlıyor. Bu durumda, bu ikisi context’in tek bir context altında birleşmesi durumunu değerlendirmemiz gerekiyor.

Son olarak, DDD’de yer alan Aggregate Root, Entity, Value object, Domain Event gibi tanımlamaları en doğru şekilde yapabilmemiz için, Bounded Context’lerimizi de en doğru şekilde tanımlamamız gerektiğini bilmemiz gerekiyor.

* **Neden ‘Bounded’ Context?**

Eric Evans’ın [**kitabının**](https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215) kapağında da belirttiği gibi, DDD’nin karmaşık domainlerde, yazılımın merkezinde yer alan o karmaşıklıkla mücadele ettiğini biliyoruz.

Yazılımda karmaşıklık ve bu karmaşıklıkla başa çıkabilme konularına baktığınızda önünüze ilk çıkan şeylerden birisi **loosely coupled (gevşek bağlı)** bir tasarımın gerekliliği olur. Burada birbirine bağlı olmayan veya çok az bağımlı olmasını istediğimiz bu parçacıkları genelde **module** olarak isimlendiriyoruz. Modüler tasarım ifadesini çokça duymuşsunuzdur. DDD’de birbirine bağımlı olmaması gereken bu modüller **bounded** yani sınırlı context’ler olarak isimlendiriliyor.

Gerçek dünyada domain’lerin kesin hatlarla belirli olmayan sınırları vardır. Bazı noktalarda benzerlik gösteren, ortak kavramlar barındıran domain’ler olabilir. Yukarıda bahsettiğimiz **Product** kavramının hem **Product** hem de **Shipment** context leri için anlamlı olması örneğindeki gibi, Product ve Shipment domain lerini kesin hatlarla ayıramıyoruz.

Ancak yazılım Dünyasında bu gevşek bağlı mimariyi kurgulayabilmemiz için sınırları kesin olarak belirli olan modüllere ihtiyacımız vardır. DDD ye göre, Product kelimesinin Product Context’inde ki anlamıyla Shipment Context’indeki anlamı farklıdır. Yani hangi context sınırları içerisindeyse ona göre anlam kazanır. **Bounded** ifadesinin bu duruma vurgu yapmak için kullanıldığını düşünüyorum.

## **Bir Bounded Context == Bir Mikroservis ?**

Bu sorunun her koşulda doğru olan bir cevabı yoktur diyebiliriz.(Yazılım mimarilerinde birçok konuda olduğu gibi)

Bir Mikroservis, bir Bounded Context’i veya onun bir bölümünü temsil edebilir. Diğer bir deyişle, bir Bounded Context birden fazla Mikroservis’te doğurabilir. Bu tamamen, söz konusu Mikroservis’in ölçeklenebilme ve bağımsız hareket edebilme gereksinimine bağlı olarak verilecek bir karardır aslında. Bunlar esasında birbirine benzer iki kavram olmakla beraber ;

**Bir Bounded Context bize domain’in sınırlarını çizerken, bir Mikroservis, domain’den etkilenmekle beraber teknik ve organizasyonel sınırları belirler.**

Özetlersek, DDD ile geliştirdiğimiz monolith uygulamamızın Mikroservis Mimari’ye dönüşümü yaparken, “Her Bounded Context için bir ve yalnızca bir Mikroservis oluşturmalıyız” gibi bir kalıbın içine girmemiz yanlış olacaktır diyebiliriz.

## Bounded Context’ler (Mikroservis’ler) Arası Veri Paylaşımı

Evet geldik bu bölümde esas bahsetmek istediğimiz konuya. Buraya kadar olan kısım aslında bu bölüme bir ön hazırlıktı diyebiliriz . Başlamadan önce buradaki esas amacımızı tek cümleyle özetlemek gerekirse ;

**Birbirlerinin verisine ihtiyaç duyan servislerimizin bu ihtiyacını, servisleri birbirlerine bağımlı hale getirmeden, sınırları(boundaries) ihlal etmeden giderebilmek,** şeklinde ifade edebiliriz.

Bu bölümde 3 örnek Bounded Context arasında ki ilişkili noktaları ve bu ilişkinin getirdiği veri paylaşımı zorunluluğunu asenkron olarak çözmemizi sağlayan bir yöntemden bahsedeceğim. Bu yöntemle alakalı Julie Lerman'ın  [**buradaki**](https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/october/data-points-a-pattern-for-sharing-data-across-domain-driven-design-bounded-contexts) yazısını incelemenizi tavsiye ederim.

Meseleyi 3 adet **basitleştirilmiş** Bounded Context üzerinden ele alalım. Bunlar **Customer, Product** ve **Discount** context’leri olsun. Customer müşteri ile alakalı iş kurallarını içerirken, Product ürün bilgileri ve Discount satılan ürünler için indirim uygulama iş kurallarını içeriyor.

Bounded Context’lerimizi ve birbiriyle ilişkili oldukları noktaları aşağıdaki gibi göstermeye çalıştım.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FjBqaFidvFGC1SxaFPq1w%2F012.jpg?alt=media&amp;token=6b48ec55-891d-4bb7-9c0a-00c231b414fe" alt=""><figcaption></figcaption></figure>

Dikkat ettiyseniz Discount context’i hem Product hem de Customer ile ilişkili durumda. Bir diğer deyişle Discount bu iki context in verisine ihtiyaç duymakta. Yuvarlak içerisinde belirttiğim diğer konseptler ise sadece o context içerisinde bir anlamı olan ve diğer context leri ilgilendirmeyen entity’ler.

Bir örnek vermek gerekirse, Product context i içerisinde **ProductCategory** adında bir entity daha var. Discount servisi indirim uygularken ürünün kategori bilgisine de ihtiyaç duysaydı bu category entity sini de ilişkili olarak göstermemiz gerekecekti. Ancak bu örnek senaryomuzda Discount servisinin müşterinin tipine göre bir ürüne indirim uygulaması isteniyor.

Örneğin bazı premium müşterilere, aynı gün yaptıkları ikinci alış verişte %50 indirim uygulanması gibi bir iş kuralımızın olduğunu düşünelim. Bu durumda Discount servisimiz, hem ürünün **Id** ve **Price** bilgisine hem de müşterinin **Id** ve **CustomerType** bilgisine ihtiyaç duymaktadır. Bu 4 bilgi haricindeki diğer bilgilerle ilgilenmediğini vurgulayarak devam edelim.

Eğer monolith yapıda ve bir tek ilişkisel veri tabanına sahip bir uygulamamız olsaydı kabaca aşağıdaki gibi tasarlayabilirdik.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FMXl5FTwZ5WiMI7LQoJTb%2F013.jpg?alt=media&amp;token=ea3655fd-df44-4003-adb1-34d9609db525" alt=""><figcaption></figcaption></figure>

Discount işlemi uygulanırken Discount tablosuna, “X ürünü için Y müşterisine tanımlı bir indirim var mı?” sorgusuyla gelerek süreci yönetebiliriz.

DDD’ye geri dönersek, biz context’lerimizi birbirinden izole ederek otonom bir yapıya bürünmelerini istiyoruz ve aradaki iletişimin event-based, yani asenkron olmasını istiyoruz. Peki bu durumda Discount servisi indirim uygularken Customer ve Product verisine ihtiyaç duyduğu anda nasıl bir yol izlemeli? CustomerId’yi kullanarak CustomerType bilgisine nasıl ulaşmalı? Customer Service’e, http isteği yaparak bu ihtiyacını pek tabi giderebilir ancak daha öncede söylediğimiz gibi bu servislerimizi birbirine bağımlı hale getirdiğinden biz bunu istemiyoruz.&#x20;

**Peki ne yapmak lazım?**

Discount servis, Product ve Customer servislerinden sadece ihtiyacı olan verilerin **read-only** bir kopyasını kendi veri tabanında saklarsa nasıl olur? Buna uygun olan yeni veri tabanı yapımız aşağıdaki gibi şekillenecektir. Dikkat ederseniz bir ilişkisel veri tabanımız varken artık 3 izole veri tabanına sahibiz. Bu veri tabanları sql/nosql/graph vb. her hangi bir tipte olabilir. Bu şuan konumuz dışında.

**Not**: DDD’de her Bounded Context için ayrı ve izole bir veri tabanı olması şartı yoktur. Aynı veri tabanında şema bazlı bir ayrıma da gidilebilir. (Product.Product, Discount.Product, Discount.Customer gibi.)

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FHe8Yal6yRm3pUV9hLmzY%2F014.jpg?alt=media&amp;token=0e534bf3-deea-4afd-8190-abe6ae28b1a8" alt=""><figcaption></figcaption></figure>

Discount servisin veri tabanında customer ve product tablolarının read-only kopyalarının olması gerektiğini belirtmiştik. Burada read-only den kastımızı biraz açalım.

Sisteme yeni bir ürün eklendiğinde **Product** service, **ProductCreated** Domain Event’ini fırlatır. Bu event’i dinleyen **Discount Service** (discount service yerine sadece bu işi yapmakla sorumlu başka bir service olması daha doğru olur ) event’i yakalayarak **Discount** servisin veri tabanındaki **Product** tablosuna bu ürünü ekler. Ancak dikkat ettiyseniz bu tabloda sadece 2 alan mevcut, **Id** ve **Price**. Daha önce belirttiğimiz gibi burada tüm product verisini tutmamıza gerek yok, sadece Discount Context’i için anlamlı olan ürün verisini saklıyoruz.

Bu product tablosuna event harici başka bir yolla veri yazma ve silme işlemi kesinlikle yapılmamalıdır. Yani, **ProductCreated**, **ProductDeleted**, **ProductUpdated**, **ProductDeactivated** vb. gibi Domain Event’lerin oluşması haricinde hiçbir şekilde bu tablo üzerinde bir değişiklik yapılmamalıdır diyebiliriz. Read-only den kastımız buydu aslında.

Eğer bu yöntemi ilk kez duyduysanız şuan kendinize şunu soruyor olmalısınız; “Discount veri tabanında ki bu Product ve Customer kopya tablolarının esas veri kaynağıyla olan senkronizasyonundan nasıl emin olacağız? Başımıza iş almıyor muyuz?” Evet alıyoruz aslında.

Sisteme yeni bir ürün eklendiğinde bu ürün discount service’in Product tablosuna eklenemezse ne olacak? Veri tabanına yazma işlemi sırasında bir hata meydana gelebileceği gibi, ilgili event bus’a hiç gönderilememiş bile olabilir. Event-Driven mimari ile uğraştıysanız kaybolmuş, akıbeti meçhul olan event problemiyle karşılaşmışsınızdır. Can sıkıcı olabiliyor.

Discount servisimizin, aslında sistemde mevcut olan bir ürün için, “Böyle bir ürün yoktur.” şeklinde bir hata dönmesini istemeyiz. Açıkçası bu yöntemin en kritik noktası işte bu veri tutarlılığını sağlayabilmek. Bunun için bazı yöntemlerden bahsedeceğiz ancak bahsetmeden önce kişisel tavsiyem olarak şunu söyleyebilirim.

Eğer Discount servis kendi read-only Product tablosuna erişir ve ilgili veriyi bulamazsa, verinin gerçek sahibi olan Product servise anlık http isteği ile erişerek bir de oradan sorgulama yapabilir. Sorgu sonucu 2 ihtimallidir. Ürün yoksa, sorun da yok. Ancak ürün varsa, bu aradaki senkronizasyonun bozulduğu anlamına gelir. Bu durumda Discount service ürün bilgisine verinin ana kaynağından eriştiği için çalışmasına devam edebilir ve buradaki senkronizasyon bozukluğunu size bildirmek için bir event fırlatabilir.

Yani, ”Ben x id’li ürünü kendi veri tabanımda bulamadım ama Product servise sorduğumda bana var olduğunu söyledi. Hayırdır?” anlamına gelen bir event’den bahsediyorum. Bu gibi event’leri dinleyen “Repair” rolünde ki farklı bir servis, bu x id’li ürünün Discount servisin Product tablosuna eklenmesini sağlayabilir. Tüm servisler bu beklenmedik durum için “Repair” servisine böyle bir event gönderebilirler.

Normal şartlarda, sistemde mevcut olmayan bir product id için discount servise bir indirim talebiyle gelinmesini beklemeyiz. Ancak aradaki senkronizasyonun bozulduğu durumlarda, önerdiğim yöntemle Discount servis çalışmasına devam edebilecek. Bu yöntemi uygulayarak servisleri birbirine bağımlı hale getirdiğimiz düşüncesine kapılmayın, çünkü Discount servis her işlemde yine ilk olarak kendi read-only tablolarına(product, customer) bakacak ve sadece çok nadir olmasını beklediğimiz senkronizasyon sorunlarında http isteği atarak ilerleyecek ve repair servisi haberdar edecek.

Kişisel önerimden bahsettiğime göre, veri tutarlılığını sağlayabilmek için uygulayabileceğimiz yöntemlerden bir kaçını çok detaya girmeden açıklayalım. Bu arada bu yöntemler, bu yazıda bahsettiğimiz veri paylaşımı metodunu olduğu kadar, tüm event-driven mimarileri ilgilendiren **data consistency** sorununun çözümü için geçerlidir.

* **Repair Service**

Yukarıda, hangi yöntemi uygularsanız uygulayın ekstra bir güvenlik önlemi olarak düşünebileceğiniz bir öneriden bahsederken değinmiş olduk aslında. Biraz daha açmak gerekirse, bütün işi read-only tabloların veri tutarlılığını sağlamak olan bir servis oluşturabiliriz. Bu servis her tetiklendiğinde esas veri kaynağı ile read-only tablolarının eşitlenmesi işini icra edecek. Bu eşitleme işlemini farklı yollarla yapabilir.

* **Domain Event’lerin Persistent(kalıcı) olarak saklanması**

Event Sourcing yönteminde, event doğrudan bir bus yerine bir stream veya NoSQL veri tabanına yazılarak kalıcı olması sağlanır. Her listener servisi kendi veri tabanında bu event’lerin durumunu takip eder.

* **Outbox Pattern**

Bu yöntemde Domain Event’ler yine doğrudan bir bus’a yazılmıyor. Bunun yerine event’i fırlatan servisin kendi veri tabanında “outbox” rolündeki bir tabloya yazılıyor. Ancak burada kritik olan nokta, event’den önce yapılan işlemin ve outbox tablosuna yazılan event’in aynı transaction’ın bir parçası olması. Yani, sisteme yeni bir ürün eklendiğinde, ürün ekleme işlemi ve ProductCreated event’inin outbox tablosuna yazılması işlemi aynı transaction’da yapılarak event’in db’ye kaydedilmesi garantileniyor.

İkinci aşama ise, outbox tablosuna yazılan bu event’lerin bağımsız bir servis tarafından alınarak event bus’a yazılmasıdır. Bu bağımsız servis bu işlemi bir kaç farklı metotla yapabilir. Konuyla ilgili Chris Richardson'ın [**burada**](https://microservices.io/patterns/data/polling-publisher.html) ve [**burada**](https://microservices.io/patterns/data/transaction-log-tailing.html) bahsettiği yöntemleri inceleyebilirsiniz.

* **Retry Policy**

Publisher servis tüm listener servislerden haberdardır ve her bir event’in ilgili listener’a başarılı bir şekilde iletildiğinden emin olur. Bu başarılı gönderim bilgisi “acknowledgement” olarak bilinir. Bu bilgiyi alana dek servisin event’i tekrar tekrar göndermesini sağlayabilirsiniz. Bu şekilde en azından event’in listener tarafından alındığından ve işlendiğinden emin olunur. Burada kritik nokta, listener servisin “acknowledgement” bilgisini hangi aşamada gönderdiğidir. En doğru olanı, event’i alıp ilgili işlemi (Discount servisin yeni eklenen ürünü read-only tabloya kaydetmesi gibi) başarıyla yaptıktan sonra bu bilgiyi iletmesi olacaktır.

Bunun dışında farklı yöntemlerde mevcut, her bir yöntemin diğerlerine göre artıları ve eksileri olduğunu da belirtmekte fayda var.

**Sonuç**

Yazılım mimarilerinde bir sorunu çözmek veya bir kazanım elde etmek için yapılan her tercih yeni zorlukları da beraberinde getiriyor. Bu neredeyse her durumda geçerli bir kural adeta. Tıpkı, yazıda bahsettiğim, bir servisin başka bir servisin ihtiyaç duyduğu verisinin read-only bir kopyasını kendi veri tabanlarında tutması yönteminde olduğu gibi. Burada kazanımımız, tamamen izole ve otonom servisler elde etmek iken (ki büyük bir kazanım), bu read-only kopyanın esas veri kaynağı ile senkronizasyonu konusu ise yeni bir zorluğu beraberinde getiriyor.


# Entegrasyon Testi

Mikroservis Mimari’de Entegrasyon Testleri Nasıl Yazılır?

**Integration Test** yazmak hatırı sayılır bir efor gerektiriyor. **Unit Test** yazmaya kıyasla daha maliyetli ve açılması gereken kilit sayısı çok daha fazla. Unit Test ile sadece servisimizin fonksiyonelliğini garanti altına alırken, diğer servislerle olan iletişimimizi garantilemek için Integration Test’e ihtiyaç duyarız.

Konu entegrasyon olunca ve işin içine bir de Mikroservis Mimari girince zorluk seviyesi daha da artıyor tabi. Eğer daha önce M**onolith** bir uygulama için **Integration Test** yazdıysanız aradaki farkı daha net görebilirsiniz.

Bu bölümde **Mikroservis Mimari** üzerine kurulu sistemlerde entegrasyon testlerinin öneminden ve konuya farklı bir bakış açısı getirerek bizi Integration Test yazmanın maliyetinden kurtaran **Consumer Driven Contracts Testing** yaklaşımını inceleyeceğiz.

### Entegrasyon Testi’ne Neden İhtiyaç Duyuyoruz? <a href="#c90c" id="c90c"></a>

Mikroservis Mimariler’de servis sayısı arttıkça, servisler arası iletişim ve entegrasyon sayısı da doğru orantılı olarak artacaktır. 10 adet servisten oluşan bir sistem ile 100 adet veya daha fazla servisin birbirleriyle konuştuğu bir sistemin karmaşıklığı ve bakım maliyetleri hiç şüphesiz aynı olmayacaktır.

Şimdi onlarca Mikroservis’den oluşan büyük ölçekli kurumsal bir uygulamayı ele alalım. **CustomerService** adında bir servisimiz olsun. Bu servis müşterilerimizle alakalı diğer servislerin ihtiyaç duyabileceği tüm servisleri sağlamakta. Dolayısıyla bu serviste yapılacak bir değişikliğin, servisi kullanan diğer servislere bildirilmesi gerekiyor. Aksi halde bu değişiklikten haberdar olmayan ilgili servis veya servisler, eğer şanslıysanız test ortamında hata verecektir. En kötü senaryoda ise, servis devam eden test süreçlerinin kapsamında değilse ancak canlı ortamda hata vermesiyle haberdar olacaksınız demektir ki bu en son isteyeceğimiz şey olur.

Aynı şekilde, eğer **CustomerService** de başka bir servisin verisine ihtiyaç duyuyorsa, o serviste yapılan değişikliğin de **CustomerService** tarafından bilinmesi gerekmekte.

Peki bu değişiklik bildirimlerini nasıl yöneteceğiz? Bunu insan eliyle manuel olarak yönetebilir miyiz? Ayrıca, değiştirdiğimiz servisin hangi servisleri etkileyeceğini biliyor muyuz? Bunun için sürekli güncel tuttuğumuz bir dokümantasyona ihtiyacımız var mı?

Eğer az sayıda Mikroservis’e sahip bir uygulamamız varsa, söz konusu ekipte küçük bir ekiptir muhtemelen ve bunu belki bir şekilde manuel ilerletebilirsiniz. Burada manuel’den kastımız ekip içerisinde, servislerde yapılan değişikliklerin, değişiklikten etkilenen servislerin sorumlularına doğrudan bildirilmesidir. Ancak onlarca hatta yüzlerce servisten bahsediyorsak bunu manuel olarak yönetmemiz söz konusu değil maalesef.

### Peki Çare Ne : Consumer Driven Contracts Testing (CDC Testing) <a href="#id-47f2" id="id-47f2"></a>

Mikroservislerinizde yaptığınız en ufak bir değişikliğin servisi kullanan **Consumer**’ ları nasıl etkilediğini bilmek gibi bir problemimiz var ve CDC testing bu problem için güzel bir çözüm olabilir.

**CDC** yaklaşımını en basit haliyle, iki servisin birbirlerine gönderdikleri verinin formatı konusunda anlaşmaya varması olarak tanımlayabiliriz. Bu yaklaşım, **Service Provider** veya **Service Consumer** tarafında yapılan her değişiklik bilgisinin anlık olarak paylaşılması prensibi üzerine kuruludur.

**CDC**’yi uygularken ki en önemli konulardan birisi Consumer ve Provider servislerini yöneten ekipler arasındaki iletişimdir. İletişim ne kadar kopuk olursa CDC’yi uygulamak da o denli zorlaşacaktır. Dolayısıyla en iyi senaryo, tüm servislerin aynı ekibin sorumluluğunda olduğu senaryodur.

Bu kadar konuştuk iyi güzel, peki bu **CDC’** yi nasıl uygulayacağız diye düşünmeye başladığınızı tahmin ederek size [**Pact**](https://docs.pact.io/) framework’den bahsetmek isterim. Pact’in detaylı implementasyonu biraz uzun kaçabileceğinden burada sadece hangi yaramıza merhem olduğu, temel yapısı ve kullanımıyla ilgili giriş seviyesinde bilgi vermeyi uygun görüyorum.

### Pact CDC Testing Framework <a href="#id-2131" id="id-2131"></a>

Pact’in offical tamınına bakarak başlayalım;

{% hint style="info" %}
[**Pact**](http://pact.io/) is a consumer-driven contract testing framework. Born out of a microservices boom, Pact was created to solve the problem of integration testing large, distributed systems.
{% endhint %}

Pact, [**Pact Foundation**](https://github.com/pact-foundation) tarafından Ruby dili kullanılarak geliştirilen açık kaynak bir CDC Testing framework’üdür. Şuan Ruby’nin yanı sıra Php, Go, C# gibi birçok dil için desteği vardır. Pact Fodundation’ın [**github sayfasını**](https://github.com/pact-foundation) incelerseniz eğer her bir dil için ayrı bir repository üzerinden ilerlendiğini görebilirsiniz.

Şimdi çok teknik detayına ve kod kısmına girmeden adım adım implementasyonu nasıl yapacağımıza bakalım.&#x20;

### Senaryo <a href="#ca6c" id="ca6c"></a>

**CustomerService** adındaki bir servisimiz ve bu servisimizi kullanan **ProductService** isminde ikinci bir servisimiz olsun. Burada **CustomerService Provider**, **ProductService** ise **Consumer** rolündeler. Yani **CustomerService**’ de yapılacak bir değişikliğin **ProductService**’i etkileyip etkilemediği konusu önem arz ediyor.

**1- Consumer Servis Tarafında Contract Oluşturma**

**Consumer** rolündeki **ProductService** servisi üzerinde eğer mevcut değilse bir test projesi oluşturuyoruz. Test yazmak istediğimiz senaryoları belirleyerek **Unit Test’**&#x6C;erimizi **PactNet’in** belirlediği formata göre ve provider servisimizi **Mock**’layarak yazıyoruz. Burada **Unit Test** ifadesinin dikkatinizi çekmesi gerekiyordu. Baştan beri entegrasyon testi deyip duruyorduk nereden çıktı bu diye düşünebilirsiniz Şöyle ki;

**CDC** ile birlikte klasik bildiğimiz Integration Test yazmanın formatından çıkmış oluyoruz aslında. Bildiğiniz gibi normalde **Integration Test** metodları web service veya veri tabanı erişimlerini **Unit Test’**&#x6C;erden farklı olarak **gerçekten** yapıyorlar. Yani bir **mocking** söz konusu değil. **CDC’**&#x79;i **Pact** ile implemente ederken de Unit Test yazar gibi, Provider servisleri mock’luyoruz çünkü bizim için artık önemli olan şey contracts yani Provider ile aramızdaki sözleşmemiz.

**Consumer**, **Provider**’a yapacağı **X,** isteğine karşılık **Y** tipinde bir yanıtı alması gerektiğini Unit Test sınıfları içerisinde **Pact'in** sağladığı fluent metodları kullanarak belirtir.

**2- Pact Contract (Sözleşme) Oluşturulması ve Provider ile Paylaşılması**

**Consumer** tarafında tüm test metotları yazıldıktan sonra testler çalıştırılır. Testler çalıştırıldıktan sonra json formatlı Contract’ımızın oluşması gerekiyor. Bu json dosyası Pact’i konfigure ederken bizim belirlediğimiz bir dizinde oluşacaktır. Test metodlarında yapılan her değişiklikte bu json dosyası otomatik olarak güncellenecek ve belirlenen dizinde her zaman güncel hali yer alacaktır. **Yani sözleşmenin sürekli güncel tutulma işini Pact halletmekte ki bu çok önemli bir konu.**

Oluşan dosyanıın json formatında ve oldukça okunabilir olması çok farklı yapıdaki servisler için bile **CDC** uygulayabilmemize olanak sağlıyor. **Go** dili ile yazılan bir **Provider** ile bir **Php** **Consumer**’ı Pact Contract’ı üzerinden el sıkışabiliyorlar.

Örnek bir Pact Contract’ı için aşağıda yer almakta. **Interactions** listesi altında iki adet **interaction** olması, iki adet test metodu yazıldığı anlamına geliyor. **Request** kısmı **Consumer**’ın yapacağı istek, **Response** ise bu isteğe karşı **Consumer**’ın **Provider**’dan beklediği yanıtı ifade eder. Görüldüğü gibi aslında açıklamaya gerek bırakmayacak kadar okunaklı bir format.  Kaynak : <https://github.com/tdshipley/pact-workshop-dotnet-core-v1>

```
{
  "consumer": {
    "name": "Consumer"
  },
  "provider": {
    "name": "Provider"
  },
  "interactions": [
    {
      "description": "A invalid GET request for Date Validation with invalid date parameter",
      "providerState": "There is data",
      "request": {
        "method": "get",
        "path": "/api/provider",
        "query": "validDateTime=lolz"
      },
      "response": {
        "status": 400,
        "headers": {
          "Content-Type": "application/json; charset=utf-8"
        },
        "body": {
          "message": "validDateTime is not a date or time"
        }
      }
    },
    {
      "description": "A valid GET request for Date Validation",
      "providerState": "There is no data",
      "request": {
        "method": "get",
        "path": "/api/provider",
        "query": "validDateTime=04/04/2018"
      },
      "response": {
        "status": 404,
        "headers": {
        }
      }
    }    
  ],
  "metadata": {
    "pactSpecification": {
      "version": "2.0.0"
    }
  }
}
```

**3- Provider’ın Sözleşmeden Haberdar Edilmesi**

Bu son aşamada artık Provider’ımıza kendisiyle anlaşma (contract) imzalamak isteyen **Consumer**’ları bildirip anlaşmaların nerede tutulduğu bilgisini vermemiz gerekiyor ki, **Provider**’ımız kendisinde yaptığı her değişiklikte hangi Consumer’ların etkilenip etkilenmeyeceğini bilsin.

Bu işlemi de yine Pact'in sağladığı **fluent** metodlar ile kolayca yapabiliyoruz. İstediğimiz kadar Consumer ve Pact Url’ini Provider’ımıza tanımlayabiliyoruz. Kod detayına girmeden konuyu toparlamadan önce son olarak [**Pact Broker**](https://github.com/pact-foundation/pact_broker) kavramından bahsedelim.

**Pact Broker Nedir?**

Oluşan json formatındaki contract’ımızı Provider ile paylaşma bölümünde ‘**Pact’i konfigure ederken bizim belirlediğimiz bir dizinde oluşacaktır.**’ demiştik. **Consumer** ve **Provider**’ın aynı ortamda bulunduğu senaryolarda Contract’ı bir dizinde saklama işimizi görecektir ancak gerçek hayat senaryolarında bu dosyayı internet ortamında, yani bir sunucu üzerinden paylaşmanız gerekecek. **Pact** bize her iki imkanı da sağlamakta. Tek yapmamız gereken json dosyamızın konumu belirtirken dizin yerine **Pact Broker**’ımızın adresini ve varsa **credential** bilgilerini yazmak olacaktır. Aynı işlemi hem **Consumer** hem **Provider** tarafında yaptıktan sonra artık servislerimiz internet üzerinde **public** veya **private** olarak tutulan bir contract üzerinde el sıkışabilecekler.

**Pact Broker** hizmetini **SaaS** olarak almak isterseniz **offical** bir hizmet de mevcut. [**https://pactflow.io/**](https://pactflow.io/) adresine girerek inceleyebilirsiniz. Eğer Pact’i ciddi olarak kullanmayı düşünürseniz mutlaka bir Pact Broker kullanmanızı öneririm.&#x20;

Ek olarak Pact Broker’ın arayüzüde Contract’ların son durumunu ve hangi servis hangi servislere bağımlı gibi verileri görebilmekte çok güzel. Örnek olarak Pact Broker’ın github sayfasından aldığım iki ekran görüntüsüyle konuyu sonlandırıyorum.<br>

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FwMuc7o2yZ4r0zvEwZr9I%2F015.png?alt=media&amp;token=6b45e975-61b7-4ab2-864f-d51d3978452d" alt=""><figcaption></figcaption></figure>

Yukarıdaki görselde tanımlı servislerimiz arasındaki ilişkiyi görebiliyorken, aşağıda ise Contract’ların son durumunu görüyoruz. En sağda yer alan **Last Verified** kolonu, Provider’ın güncel Contract’ı ne zaman **verify** ettiğini göstermekte. Kırmızı renk anlaşmanın bozulduğuna işaret ediyor.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F7QkNVlgZFV5ykFByuRDt%2F016.png?alt=media&amp;token=40d4c251-dda9-49f4-b46a-2c1425b22fff" alt=""><figcaption></figcaption></figure>

### **Toparlarsak** <a href="#id-826e" id="id-826e"></a>

Bu bölümde Mikroservis Mimari’lerdeki en zorlu konulardan birisi olan Integration Test konusuna farklı bir bakış getiren **Consumer Driven Contrats** yaklaşımını ve bu yaklaşımı uygulayabilmek için kullanılan **Pact** framework’ünü giriş seviyesinde inceledik.&#x20;

Eğer ürünlerinizi Mikroservis Mimari ile geliştiriyorsanız, **Pact** veya muadili farklı bir framework’ü yazılım geliştirme yaşam döngünüzün olmazsa olmaz bir parçası haline getirmenizi tavsiye ederim.


# Loglama ve Monitoring

Mikroservis Mimari’de Loglama ve Monitoring

Bu bölümde loglama için mimarimizi nasıl oluşturmalıyız, **best practice**’ler nelerdir sorularına yanıt arayacağız. Burada bahsedeceğim konuların bir çoğu sadece **Mikroservis** uygulamalara özel şeyler olmayacak, dolayısıyla **Monolith** mimaride uygulama geliştirenler için de ilgi çekici olacağını düşünüyorum. Konuyu iki ana başlıkta ele alacağız;

* Loglama Üzerine Genel Tavsiyeler
* Uçtan Uca Loglama Mimarisi

## Loglama Üzerine Genel Tavsiyeler

Mikroservis Mimari’ leri dağıtık sistemlerin bir türü olarak ele alabiliriz.Dağıtık sistemlerde her bir servisi ve bu servisin üzerinde çalıştığı sunucuyu **trace** etmek **(**&#x69;zleme&#x6B;**),** beklenmedik durumlarda hatanın kaynağına hızlı ve etkili şekilde inebilmek için çok önemlidir.

Servislerimizin her birisi farklı bir sunucuda sunulurken, oluşan uygulama loglarımız da haliyle dağıtık yapıda olacaktır. Buna ek olarak bir de **cloud** üzerinde **auto-scaled** bir yapınız varsa, o zaman hangi log hangi sunucuda ve ne zaman oluşmuş gibi soruların yanıtını almak için biraz daha fazla efor harcamanız gerekiyor. Zira bildiğiniz gibi **auto-scale** yapıda yük durumuna göre dinamik olarak yeni sunucular çok kısa sürede devreye alınıp aynı şekilde kapatılabiliyor. Loglama mimarimizi, bu kapatılan sunucularda log kaybı yaşamamak üzere kurgulamamız gerekmekte. Yani kısaca cluster’ınızın auto-scale olup olmaması da mimariyi kurgularken göz önünde bulundurmamız gereken konulardan birisi olmalı.

### Logların Merkezileştirilmesi <a href="#f252" id="f252"></a>

Yapımız dağıtık bir yapı olduğundan, ilk düşünmemiz gereken konu tüm servislerimizin ürettiği logların tek yerden erişilebilir olmasıdır. Bir servisin logunu file’a, bir diğerinin DB’ye bir başkasının kuyruğa yazdığı bir ortamda oluşan bir hatanın kaynağına inmek saatler alabilir.

Merkezileştirme için çeşitli yöntemler mevcut. Mimari bölümünde biraz daha detaylı ele alacağımız için burada sadece kaçınmamız gereken bir **bad practice’**&#x64;en bahsetmek isterim.

Mikroservis Mimari’yi uygularken, isteriz ki servislerimiz atomik olsun, yani sadece bir işe, bir domain’e odaklansın. Diğer servislere bağımlılığı sıfır noktasında olsun. Hal böyleyken her türlü ihtiyaç için irili ufaklı servisler oluşturmaya başlarız. İş loglamaya geldiğinde de yine bir http log service oluşturup loglama işini de bu servise yükleyerek diğer tüm servislerin bu servis üzerinden log atmasını isteyebiliriz. İlk bakışta her şey normalmiş gibi gözükse de servis sayısı, dolayısıyla üretilen log miktarı arttıkça loglama işlemi için oluşan http trafiği baş ağrısı olabiliyor. Yani bu maddeden çıkaracağımız ders, loglama işini üstlenen bir http service oluşturmaktan kaçınmamız gerektiği.

### Merkezileştirme İçin Aggregation Tool Kullanma <a href="#id-77df" id="id-77df"></a>

**Log Aggregation** araçları, tüm loglarımızı tek bir ortak lokasyonda ve benzer formatta birleştirme ihtiyacı üzerine ortaya çıkmıştır. Bu birleştirme işi için farklı yöntemler mevcut. Burada seçeceğiniz yöntem, servis loglarınızı nerede ve nasıl tuttuğunuza göre belirlenecektir.

Örneğin, siz her servisin kendi sunucusunda bir dizine .txt olarak log atmasına karar verdiniz. Bu logları birleştirme için bir job yazar, belirli aralıklarla tek ortak bir dizine tüm txt’leri toplayabilirsiniz. Tercih kötü olsa bile sonuçta bir **log aggregation** yapmış olursunuz aslında.

Daha doğru olan ise, bu iş için geliştirilen ücretli veya ücretsiz bir araç kullanmanız yönünde. **ELK (elastic search, logstash,kibana)** stack’inin aggregation aracı olan **logstash**’i önerebilirim mesela. ELK’dan, mimari bölümde bahsedeceğimiz için burada fazla detaya girmiyorum

### Log’daki Tüm Alanların Aranabilir Olması <a href="#id-295f" id="id-295f"></a>

Loglarınızı sorgularken bazı alanlar üzerinden daha sık sorgulama yapmanız gayet doğaldır. Ancak siz her durumda mevcut alanların tümü üzerinden sorgulama yapabilecek ve hızlıca yanıt alabilecek bir yapı oluşturmaya odaklanırsanız iyi edersiniz.

Hız için veri tabanı üzerinde index oluşturma tabi ilk aklımıza gelen çözüm. **CustomerId**, **UserId**, **LogLevel** gibi alanlar üzerinden index’lenme olmazsa olmazdır, ancak kritik bir anda örneğin **InstanceId** alanı üzerinden sorgulama yapmanız gerekirse, dakikalarca beklemek biraz can sıkıcı olabilir.

Eğer çözüm index oluşturmaksa neden tüm alanlar için oluşturmuyoruz diye düşünebilirsiniz. Index’leme işi maliyetlidir. Çok fazla veya çok büyük boyutlu index’ler memory’de büyüklüğüne göre yer kaplayacaktır. Üstelik bununla da kalmaz, her bir insert/delete/update komutundan sonra bu indexlerin güncellenmesi gerekmektedir. Bu da sizin insert/delete/update sürelerinizin uzamasına yol açabilir.

Ancak bu index’leme işini uygulama veri tabanında değil de ,bir log aggregation aracı üzerinde yaparsanız performans kaybının önüne geçebilirsiniz.

### Log Seviyesinin (Log Level) Dinamik Ayarlanması <a href="#id-3716" id="id-3716"></a>

Atılan her bir satır log’un mevcut kaynaklarınızı tükettiğini ve aynı zamanda log sorgulama maliyetinizi (süresini) artırdığını unutmamanız gerekiyor. Bu bağlamda, servislerimiz ayaktayken, **runtime’**&#x64;a log seviyemizi dinamik olarak,uygulamamızı kesintiye uğratmadan değiştirmek isteyebiliriz.Elbette kullandığımız yardımcı kütüphanenin (varsa) bunu destekliyor olması gerekmekte.

Bu özelliği ağırlıklı olarak **Production** ortamımızda kullanabiliriz. Örneğin geçici bir süreliğine Debug seviyesinde log atılmasını isteyebiliriz. Servisimiz ayağı kalkarken en detaylı log seviyesini pasife çekip, sonrasında aktif hale getirerek aslında bize bir faydası dokunmayan, gereksiz bir sürü logdan kurtulabiliriz.

### Asenkron Loglama <a href="#id-2bc2" id="id-2bc2"></a>

Loglama işlemini hangi yolla yaparsanız yapın, log’u atacak olan birimin asenkron çalışması uygulama performansı açısından önemlidir.

Asenkron loglamada, loglamayı yapacak olan **logger thread**, o an yürütülmekte olan transaction’ın (http isteğinin) thread’ini block’lamayacağı için herhangi bir performans kaybına neden olmayacaktır. Ek olarak uygulamanızın loglama işleminin sonucuyla da ilgilenmemesi gerekiyor. Bir başka deyişle loglar **fire-and-forget** prensibi ile gönderilmelidir.

### CorrelationId Kullanımı <a href="#id-9179" id="id-9179"></a>

Bir transaction’ın icra edilmesi için arka planda 3–5 farklı web servisin birbirlerini tetiklediği bir senaryoyu ele alalım. Burada yapılan işlem aslında tek bir işlem. Örneğin bir satın alma işlemi. Ancak arka planda 5 farklı servis çalışmakta ve, 5 adet log atıldığını biliyoruz. Bu işlemin loglarına erişmek istediğimizde bu 5 adet log için bir grup numarası olsaydı ve bu no ile sorgulama yaptığımızda sadece bu 5 adet logu görebilseydik güzel olurdu değil mi?

Bu gruplamayı yapmak için **X-Correlation-Id** http header’ını kullanabiliriz. Bu header’a işlem bazında **unique** bir değer set etmemiz gerekmekte. Ek olarak log tablomuza da CorrelationId adında bir alanda eklememiz gerekiyor tabi. Artık geriye, bu header’ı her servis **request** ve **response’**&#x75;için doğru şekilde set etmek olacaktır. Örnek senaryomuzdaki 5 adet servisten her birisi bir sonraki servise bu CorrelationId değerini geçecektir. Kulaktan kulağa oyunu gibi düşünebilirsiniz.

### Detaylı ve Anlaşılabilir Log <a href="#id-72f8" id="id-72f8"></a>

Gün içinde bir servisin loglarını inceleme gereği duyuyorsak, bir şeyler ters gidiyor demektir, tabi istisnai durumlar olabilir. Gerek development aşamasında gerekse production ortamımızda loglar tabiri caizse elimiz ayağımız oluyor. Tabi yeteri kadar detaylı bilgi verebildikleri zaman. Bu da yine bizim elimizde olan bir şey. Özellikle **error log**’ları mümkün olduğunca detaylı ve önemli bilgi içermelidir. Detaylı yanında önemli de dedim çünkü gereksiz bir sürü detay içeren ama hatanın kaynağına inmeye yardımcı olacak bilgiyi içermeyen logun kimseye bir faydası olmayacaktır.

Sözün özü, eğer loglarınızı incelerken “Keşke şu bilgi de elimizde olsaydı” diye iç geçiriyorsanız, o bilgi için de ek bir alan açmanın zamanı gelmiş demektir.

### Log Zamanı İçin Utc Time Kullanımı <a href="#d9fe" id="d9fe"></a>

Özellikle servislerin cloud üzerinde sunulduğu senaryolarda, mevcut sunucuların veya yük oluşması anında devreye alınacak yeni sunucuların hangi time zone’da olacağıyla ilgilenmek istemezsiniz. Sizin için önemli olan sunucunun performansı ve yüksek erişilebilirliği olacaktır.

Ancak iş loglarınızı sorgulamaya gelince, log zamanının hangi time zone’a göre atılacağı konusu önem arz ediyor. Zamana göre order by ettiğiniz logların işlem sırasına göre hatalı olarak gelmesi istemezsiniz. Burada tavsiyem Utc time kullanmanızdır. Böylece çok farklı lokasyonlardaki servislerden atılan loglarda bile zaman karmaşası yaşamamış olursunuz. Bu arada eğer sizin için logu atan sunucunun local zamanı da önemliyse, log veri tabanınıza **TimeZone** adında opsiyonel bir alan ekleyip time zone bilgisini de buraya yazabilirsiniz.

### Instance Id Ekleme <a href="#b0e8" id="b0e8"></a>

Eğer servislerinizi herhangi bir cloud provider üzerinden sunuyorsanız ve auto-scaling özelliğini kullanıyorsanız, yukarıda da bahsettiğim gibi yük durumuna göre sürekli yeni sunucular (instance) eklenip çıkarılacaktır. Log’un hangi instance’dan atıldığı, logu atan sunucunun hala aktif olup olmadığı gibi konular sizin için önemliyse, logunuza **InstanceId** alanını ekleyerek bu sorunu çözebilirsiniz.

### Log Alert Sistemi <a href="#id-8b19" id="id-8b19"></a>

Loglama alt yapınız artık olgunlaştı, loglarınız sorunsuz şekilde akıyor, sorgular gayet hızlı çalışıyor ne mutlu size. Artık işi bir adım öteye taşımak gerekiyor.

Eğer canlı ortamda oluşan hatalarınız için biraz daha proaktif olmak ve daha hızlı aksiyon almak istiyorsanız mutlaka bir alarm sistemini devreye almanız gerekiyor. Bu sistemi sağlayan ücretli ücretsiz birçok **third party** araç mevcut olmakla birlikte kendi implementasyonunuzu da pek ala yapabilirsiniz tabi.

Bu tarz alarm yapılarıyla örneğin, gelen log daki **LogDetail** alanında “**DB Connection Timeout**” hatası geçiyorsa şu kişi veya kişilere slack’ten mesaj at veya sms at gibi aksiyonlar alabildiğimiz için oldukça faydalı olduğunu söyleyebilirim.

Alarm konusu için [**Seq**](https://getseq.net/) i incelemenizi öneririm. Tabi [**ELK** ](https://www.elastic.co/elk-stack)ile de veri değişikliklerini izleyerek aynı şekilde alarm kuralları oluşturabilmeniz mümkün.

## Uçtan Uca Loglama Mimarisi <a href="#id-67d8" id="id-67d8"></a>

Bu bölümde, yukarıda yaptığımız öneriler ışığında örnek bir mimari tasarlayıp, çizdiğim diagram üzerinden yorumlamaya çalışacağım.

Hatırlarsanız loglamayı bir servis üzerinden http request ile yapmanın kötü bir fikir olduğundan bahsetmiştik. Ancak aynı zamanda logları bir şekilde merkezileştirmemiz gerektiğini de söyledik. Yapmamız gereken şey çokta karmaşık değil aslında.

Her Mikroservis, oluşturduğu logları aracı bir başka http servis olmaksızın asekron olarak bir kuyruğa gönderebilir. Buradaki kuyruk, **Apache** **Kafka** veya **RabbitMQ** gibi bir **message broker** olabileceği gibi, kuyruk kullanmadan doğrudan bir **RDBMS** veya **NoSQL** veri tabanı da olabilir. Bu tamamen sizin log yoğunluğuna bağlı olarak yaptığınız tasarıma kalmış. Benim tavsiyem, **Kafka** veya **RabbitMQ** ikilisinden birini kullanmanız yönünde olur. Eğer doğrudan bir veri tabanına yazacaksanız da bu RDBMS yerine bir NoSQL veri tabanı olmalı.

Loglarınızı doğrudan bir kuyruğa göndererek veri tabanı sunucunuzu ekstra ve büyük bir yükten kurtarmış olursunuz. Veri tabanı sunucunuz sizin en değerli kaynağınızdır. ve unutmayın DB sunucuları ram’i sever yani bol bol kullanır.

Bir diğer aklıma gelen konu da uygulamanız ayağı kalkarken, henüz veri tabanı bağlantısı yapılmadan önce loglamaya değer bazı bilgileriniz olabilir ancak veri tabanı bağlantısı henüz sağlanmadığı için bu bilgileri loglayamayacaksınız.

Kuyruk yapıları AMQP protokolünü desteklerler. Bu protokol Http’nin aksine asenkron çalışır ve mesajları alıcısına teslim etme garantisi verir. Tabi sizin kuyruğu nasıl konfigüre ettiğiniz de önemlidir. Servisler arası iletişimi incelediğimiz bölümde AMQP’den daha detaylı bahsetmiştik hatırlarsanız.

Tüm bu bilgiler ışığında çizdiğim aşağıdaki basit mimariyi siz de uygulamalarınız için rahatlıkla uygulayabilirsiniz.

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fjyt250I60v8Y7YKdG2wL%2F017.png?alt=media&amp;token=acda1cbc-0412-46f8-885f-120d75ab9743" alt=""><figcaption></figcaption></figure>

Son olarak mimariyi oluşturan bu 5 parçadan kısaca bahsetmek gerekirse;

### Microservices <a href="#e2bd" id="e2bd"></a>

Farklı format ve yoğunluklarda loglar üreten ve kuyruğa gönderen mevcut microservislerimiz mimarinin ilk bacağını oluşturmakta. Dikkat ederseniz servisler ve kuyruk arasında başka aracı bir servis bulunmuyor.

### **Message Queue** <a href="#e78b" id="e78b"></a>

Mikroservis’lerimizin ürettikleri logları **publish** ettikleri kuyruğu tanımladığımız message broker’ımız. Log yoğunluğuna göre bu broker’ları da yatayda ölçekleyebilirsiniz yalnız, Kafka yatayda ölçeklenebiliyorken yanılmıyorsam RabbitMQ bu imkanı vermiyor. RabbitMQ da, iki farklı sunucu kurup aktif-aktif çalışmasını sağlayabiliyorsunuz ancak yükü 2 sunucu arasında dağıtarak yatayda ölçekleneyim diyemiyorsunuz.

### **Aggregation Tool** <a href="#e632" id="e632"></a>

Aslında ELK bütün olarak bir log aggregation aracıdır demek de yanlış olmaz. **Logstash**, logları ilk karşılayan, isteğinize göre manipüle edebilen ve sonrasında Elasticsearch’e gönderen taraf olduğu için ben, Logstash ELK stack’inin log aggregation tool’udur demeyi tercih ediyorum.

### **NoSQL Document DB** <a href="#id-4d3b" id="id-4d3b"></a>

Elasticsearch, bir arama motoru gibi çalışmak üzere optimize edilmiş, NoSQL document tipi veri tabanıdır. ELK stack’inde logların fiziksel olarak saklandığı, indexlendiği ve sorgulandığı yer burasıdır.

### Visualization Tool <a href="#id-2b45" id="id-2b45"></a>

ELK stack’ini tercih ettiğimiz için loglarımızı listelemek, sorgulamak ve çeşitli faydalı grafiklerden faydalanmak için bu stack’in sunmuş olduğu Kibana visualiztion tool’unu kullanıyoruz. Kibana, kullanışlı arayüzü, log sorgularken işimizi kolaylaştıran query syntax’ı, oluşturulan log raporlarını excel export edebilme gibi birçok özelliği bünyesinde barındırıyor.


# Sonuç

Mikroservis Mimari'nin, bir bütünü küçük parçalara ayırarak yönetme fikrini akla getirmesinden ötürü cezbedici bir tarafının olduğu kesin.  Bu cezbedicilik ve büyük firmaların ardarda yaptığı Mikroservis Mimari dönüşümleri **hype** rüzgarını da beraberinde getirdi. Bunun sonuncunda da bu dönüşümü başarıyla tamamlayanların yanında hatırı sayılır bir miktarda da başarısızlık hikayesi ortaya çıkmış oldu.&#x20;

Küçük veya orta büyüklükte, henüz canlıya bile çıkmamış , hatta belki ölçeklenme ihtiyacı bile olmayan uygulamalarımızı Mikroservis Mimari'ye dönüştürmek için kolları sıvadık ve gün sonunda aynı ortak veri tabanını kullanan, birbirleriyle http isteği yaparak haberleşen, dolayısıyla bir birlerine göbekten bağlı olan web servislerimiz oldu.

Kişisel bloğumdaki yazı dizisine ve bu e-book'u hazırlamaya başlarken ki motivasyonum, az da olsa biraz farkındalık oluşturabilmek ve henüz işe koyulmamış, araştırma safhasındaki ekiplerin aklına 'acaba' sorusunu getirebilmekti.&#x20;

Acaba ihtiyacınız olan şey tam olarak bu mu, yoksa hype rüzgarına mı kapıldınız?&#x20;

Kaynak ve Teşekkürler  = <https://medium.com/@suadev>&#x20;


# GIT-GITHUB


# Git - Github - Giriş

* Dağıtık bir versiyon kontrol sistemidir.
* Açık kaynak kodlu ve ücretsiz.
* Hızlı kontrol sistemi.
* Versiyonlama, değişikliklerin takibini sağlayabildiğimiz bir yöntem.

{% hint style="info" %}
Misal bir uygulamanın, 2.versiyonu 1.versiyonuna göre bazı değişikliklere sahip olabilir.
{% endhint %}

* Takım çalışması için kullanışlı.
* Dosyaların üzerinde yapılan değişiklikler görüntülenebilir.

#### Diğer Kavramlar

* Repository : Kod deposu, veri deposudur. Projelerimizin versiyon kontrolünü yapabilmek adına oluşturulmaktadır. Tüm dosyalarımızın üzerinde yapılan değişiklikleri görebileceğiz. Repo oluşturmak için "git init" komutunu kullanıyoruz.
* Working Directory : Çalışmakta olduğumuz dizindir. Hangi dizinde çalışılacaksa, repo oluşturulmalıdır.
* Staging Area : Güncelleme yaptığımız, dosyaların bulunduğu yer. Dosyalar üzerinde güncelleme yaptıktan sonra, working directory 'den Staging area 'ya taşıyoruz.
* Commit : Yapılan değişikliklerin tarafımızca onaylanması.
* Working Directory 'de çalıştığımız dosyaları güncelledikten sonra, staging arae 'ya alıyoruz. Buradan da repository 'e gönderiyoruz.

resim gelecek

### Staging Area

GIT 'de değişikliklerin, kayıt altına alındığı alandır. Staging area, proje dosyalarımızda bir dizi değişikliği yeni bir versiyon olarak işaretlemeden önce kayıt altında tuttuğumuz veri tabanı olarak tanımlayabiliriz. GIT status ile proje dosyalarımızın durumunu görebiliriz. Git status ile üzerinde çalışılan repository 'nin,  O anki durumu görüntülenir. Üzerinde değişiklik yapılan dosyalar, yeni eklenmiş dosyalar ve commit komutu uygulanmamış konsol üzerinde listelenir. Git add ile değişiklik yapılan/yeni eklenen dosyaları eklersek dosyalar/dizinler staging area 'ya taşınacaktır.

```
git add .  > Bulunduğumuz dizindeki dosyaları tamamını staging area aktaracaktır.
```

### Git Commit

Git 'de eklediğimiz dosyaları kalıcı olarak git veri tabanına işlemeye commit denilmektedir. Proje 'de belli başlı işlemler yapıldıktan sonra dosyaları commit etmek gerekir. Yapılan değişiklikleri kimlerin tarafından yapıldığını anlamak için git config ile username ve mail adresini tanımlamak gerekmektedir. &#x20;

{% hint style="info" %}
git commit -m \[message]&#x20;
{% endhint %}

### Git add

Git ile versiyon kontrolü altına aldığımız projemize, dosya eklediğimizde, dosya sildiğimizde veya var olan dosyanın içeriğini değiştirdiğimizde bu değişiklikler, git tarafından otomatik olarak kontrol - takip edilmez. Git 'in bu dosyaları takip etmesi için git add komutu ile bu dosyaları önce git 'e tanımlamamız gerekir.

* git config global : Geçerli olan kullanıcının, tüm projeler için genel yapılandırmalar. .gitconfig dosyası içerisinde saklanır.
* git config system : Bilgisayardaki tüm kullanıcılar, tüm repoların ayarlarının kontrol edilip, bulunduğu kısımdır.

{% embed url="<https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-config>" %}


# Branch

* Branch'ler projemize dallara ayırmamızı sağlar.

Misal, Projemize yeni bir özellik eklemek istiyoruz. Ama projenin yaşamaması, yeni özelliği bu projeyi etkilememesini istiyoruz. Ama bu özelliği de test etmek istiyoruz. Gibi durumlarda kullanabilir. Projemizin bütünlüğünü bozmadan değişiklikler yapmak istersek. Branch bu konuda bize yardımcı olacaktır.

git init komutunu verdiğimizde bizim için master adında branch oluşuyor. Eğer biz ayarlarımızda bir değişiklik yapmazsak, bütün geliştirmeyi master branch üzerinde yapıyoruz. Geliştirmeler farklı bir branch üzerinde yapılır, bir problem olmazsa master branch ile merge edilebilir (birleştirir)

{% hint style="info" %}
Bir branch içerisinde, farklı branch 'ler oluşturulabilir.
{% endhint %}

<mark style="background-color:orange;">Bir branch oluşturduğumuzda mevcut projemizin, en son halini bu branch 'e kopyalanır.</mark>

```
git branch -l # Var olan branch listesini gösterir.
git branch database # Database branch oluşturur.
git checkout -b web # Web branch yoksa oluşturur, mevcutsa o branch 'e geçer.
git checkout [branch adı] # Belirttiğimiz branch 'e geçeriz.
```

{% hint style="info" %}
Üzerinde bulunduğumuz branch 'deki en son alınan commit 'e head denir.
{% endhint %}

resim gelecek


# Merge

Branch 'imizi hangi branch ile birleştirmek istiyorsak, o branch 'e geçiyoruz. Örneğin, Web branch 'imizi master'i ile birleştirmek istiyorsak, master branch 'ine geçip,

```
master$> git merge web # Web kısmına, birleştirmek istediğimiz farklı bir branch 'ide yazabiliriz.
```

resim gelecek

```
git branch -d web # Web branch 'ini silmek istersek. Bu komutu kullanıyoruz.git branch -d web # Web branch 'ini silmek istersek. Bu komutu kullanıyoruz.
```

Head : Bulunduğumuz branch 'de en son commit 'i gösterir. Ve bu commit 'in hangi branch'lerde olduğunu gösterir.

### fast forward merge

resim gelecek

Feature branch 'iniz master 'a merge olacağı anda, eğer master üzerinde bir değişiklik (commit) olmamışsa git varsayılan olarak master hattının son commit hash 'i olarak, feature branch'inin hash 'ini alır. Bu duruma fast forward merge denir. Bu işlem sonrasında, sanki değişiklikler master branch de yapılmış gibi history oluşur. Merge işlemi sırasında --no-ff parametresi verilirse merge işlemini daha anlaşılabilir history (log) tutar.


# Cheat Sheet


# Encoding vs Encryption vs Tokenization

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FriEsHR3P7gjPnpqyHGAb%2FEncoding%20vs%20Encryption%20vs%20Tokenization.gif?alt=media&amp;token=1d935b6f-ac02-4df0-bce1-86702a061afa" alt=""><figcaption></figcaption></figure>


# Cloud Services

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F0Q82xjmnNTPI4p5gBUS6%2Fcloud-services.jpg?alt=media&amp;token=f428b663-2a8e-4a2f-8e64-26c06e664adc" alt=""><figcaption></figcaption></figure>


# Devops-CI-CD

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FBygxgRlUcIaAvtKF21Uu%2FDevops-CI-CD.png?alt=media&amp;token=e668cb1f-4427-41ca-841a-b937f05be78c" alt=""><figcaption></figcaption></figure>


# CI-CD

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FMzD78mfLq5ZEbhbqkbP5%2FCI-CD.gif?alt=media&amp;token=07b98d16-c4a3-4cd2-abb7-fc13b399e8cc" alt=""><figcaption></figcaption></figure>


# Cloud Database Landscape

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FmrUP4WHwMytphSmE8bi3%2FCloud%20Database%20Landscape.jpeg?alt=media&amp;token=07ef1b88-b0a2-4603-bf65-5af8085d9cd6" alt=""><figcaption></figcaption></figure>


# Cloud Disaster Recovery Strategies

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FceU7U0EG9d2EYjQz42bh%2FCloud%20Disaster%20Recovery%20Strategies.jpeg?alt=media&amp;token=769633d3-0b83-46ca-8309-943b862984a0" alt=""><figcaption></figcaption></figure>


# Cloud IAM Best Practice

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F2OGAKEr6EsuawkOgd9YJ%2FCloud%20IAM%20Best%20Practice.jfif?alt=media&amp;token=272e00bf-6f41-405e-819f-d965a1e30f1f" alt=""><figcaption></figcaption></figure>


# Cloud Native

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FDt9uxVc1XZfavd5Nc0HZ%2FCloud%20Native.jfif?alt=media&amp;token=7619740a-13be-41b2-8ebe-74a91586c39c" alt=""><figcaption></figcaption></figure>


# Components of A URL

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FNJwha8rrDXVwkFQHmBT3%2FComponents%20of%20A%20URL.jfif?alt=media&amp;token=60f3013c-3d6d-4f83-9773-f46c825e938e" alt=""><figcaption></figcaption></figure>


# Components of Kubernetes

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F4WoSuZEho9AHDCB3rcgD%2FComponents%20of%20Kubernetes.jpeg?alt=media&amp;token=8bd35f43-e1af-413c-97d5-664fd44b4a8a" alt=""><figcaption></figcaption></figure>


# Data Stracture CheatSheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FK88fP1ykEDmSfgp2YbFJ%2FData%20Stracture%20CheatSheet.jfif?alt=media&amp;token=e1cdb0bc-a04b-438e-8b26-4ce829df7a1e" alt=""><figcaption></figcaption></figure>


# Database Connections Pool

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FIc1yniU0vC8LyZN1LaQp%2FDatabase%20Connections%20Pool.jfif?alt=media&amp;token=a171b751-ff8f-48d3-bb9d-933f38d9e272" alt=""><figcaption></figcaption></figure>


# Devops and Cloud Key Metric

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F6BGZP4fcMLrlP6eTQTxS%2FDevops%20and%20Cloud%20Key%20Metric.jfif?alt=media&amp;token=9f8811c8-7f7a-442b-9551-a45c182f0929" alt=""><figcaption></figcaption></figure>


# Devops Life Cycle

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Ff2hHvppJoNWBJA2cap4i%2FDevops%20Life%20Cycle.jpeg?alt=media&amp;token=0a55f653-ca0f-4b6a-a259-7909c962e54e" alt=""><figcaption></figcaption></figure>


# DevOps SRE Raod Map

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Ft02SVi0DrmXXrCcPKVXr%2FDevops%20and%20Cloud%20Key%20Metric.jfif?alt=media&amp;token=175764e2-0ae6-476d-b8f7-661fad98f9e0" alt=""><figcaption></figcaption></figure>


# Doceker vs Kubernetes

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FtXGJD7zUPy2h9DDpZd5p%2FDoceker%20vs%20Kubernetes.jpeg?alt=media&amp;token=82a3f783-80f4-4dc9-b4f8-ac041e9fe0f5" alt=""><figcaption></figcaption></figure>


# Forward Proxy vs Reverse Proxy

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FkHHMf0V85VIQl3fbYurk%2FForward%20Proxy%20vs%20Reverse%20Proxy.gif?alt=media&amp;token=687a6f1f-f120-4bd1-89ce-c4141cf8d830" alt=""><figcaption></figcaption></figure>


# Git Cheat Sheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FqYbaoyE9eajvkbEDkcSk%2FGit%20Cheat%20Sheet.jfif?alt=media&amp;token=99d14364-d76c-4f4f-a8b2-8aabbe6b93d7" alt=""><figcaption></figcaption></figure>


# Helm Cheat Sheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FCPDoyNVtcQXBMEjmyFUG%2FHelm%20Cheat%20Sheet.png?alt=media&amp;token=3cb7344a-74e9-42f8-9e15-905c922059c7" alt=""><figcaption></figcaption></figure>


# How DNS Work

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fjr6rBu1Baybv0xd58MJP%2FHow%20DNS%20Work.jfif?alt=media&amp;token=6bfb5749-4624-4ab2-b0b0-3cc17eb792e1" alt=""><figcaption></figcaption></figure>


# HTTP Status Code

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FRLYCASeKduoEsiFasdsW%2FHTTP%20Status%20Code.jpg?alt=media&amp;token=d65e8528-2f31-48b3-aa2f-2c605d65b9e4" alt=""><figcaption></figcaption></figure>


# Kubernetes Commands Cheat Sheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FKjY17TvvzoMybhKqt804%2FKubernetes%20Commands%20Cheat%20Sheet.jpeg?alt=media&amp;token=8be8fde6-d9d1-421b-9a8a-2ae381d342b8" alt=""><figcaption></figcaption></figure>


# Kubernetes Cost Reduction Tecniques

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FAFXiXKIuyKzv9eJqAo7a%2FKubernetes%20Cost%20Reduction%20Tecniques.jfif?alt=media&amp;token=d9b3bbf6-c0d3-4291-957c-cf65dc263ed2" alt=""><figcaption></figcaption></figure>


# Kubernetes Ecosystem

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F14MAigdDdZ3Us8i8tzqX%2FKubernetes%20Ecosystem.jpeg?alt=media&amp;token=270152d8-ce47-4e62-af40-6cae2d00ee33" alt=""><figcaption></figcaption></figure>


# Kubernetes Porduction Reality

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FtCqpP4ul7fnLjwvkp41B%2FKubernetes%20Porduction%20Reality.jfif?alt=media&amp;token=bbe137a2-3ce2-44ee-ab1c-5bbb8873dd80" alt=""><figcaption></figcaption></figure>


# Kubernetes Troubleshooting Cheat Sheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FqqdnPlpActCligSzidgD%2FKubernetes%20Troubleshooting%20Cheat%20Sheet.jpeg?alt=media&amp;token=75a34d62-ff70-4dbb-ad28-e20bea7971d2" alt=""><figcaption></figcaption></figure>


# Linux Command Cheat Sheat

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FFCr7i02Lr2HulRAgCv19%2FLinux%20Command%20Cheat%20Sheat.jfif?alt=media&amp;token=9015fdd7-2345-4ffc-9029-5caec18f326d" alt=""><figcaption></figcaption></figure>


# Microservice Best Practice

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fvq1eB9jvbXR3YBFXIPdr%2FMicroservis%20Best%20Practice.jfif?alt=media&amp;token=cf92ee83-160b-4e5a-8fe8-7d944d3707e6" alt=""><figcaption></figcaption></figure>


# Monolithic vs Microservice Architechture

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F1G0bhJfIJSpYYBWDHlIo%2FMonolithic%20vs%20Microservice%20Architechture.jpg?alt=media&amp;token=af04b523-9c08-49f0-b9fb-d73833ae57d0" alt=""><figcaption></figcaption></figure>


# Multi Cloud Databese Picker

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FdL4wLEIXmmidN0W0FWYX%2FMulti%20Cloud%20Databese%20Picker.jfif?alt=media&amp;token=471723df-48a6-42f6-9e00-bf38fa095efa" alt=""><figcaption></figcaption></figure>


# Never ingnore these 7 commands

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FvcUkQikhMYttfKLQLhGj%2FNever%20ingnore%20these%207%20commands.gif?alt=media&amp;token=b5d41eec-7ccd-4f97-9499-a1d2b40cc096" alt=""><figcaption></figcaption></figure>


# OpenShift Archtitect

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FJ0VAsYGwZCE5OlPXJS3z%2FOpenShift%20Archtitect.png?alt=media&amp;token=331e39bb-34a6-466c-97fc-f1e4d91097bd" alt=""><figcaption></figcaption></figure>


# Microservice RoadMap

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FCga9u8fCnvW5BhkRGyly%2FMicroservice%20RoadMap.png?alt=media&amp;token=19891716-1aad-4ffd-b2a1-d87aaa18d073" alt=""><figcaption></figcaption></figure>


# Scrum vs Kanban

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F3Iolcq1K2IpEORn2q0w4%2FScrum%20vs%20Kanban.png?alt=media&amp;token=1c90b03a-04bd-42e3-bb58-ef4804415efb" alt=""><figcaption></figcaption></figure>


# Software Architecture Styles

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FMZ2HJZyLIZRD5aBeJUr2%2FSoftware%20Architecture%20Styles.jfif?alt=media&amp;token=38bca6da-b1e4-46e2-bf2c-2e0bfbf4421c" alt=""><figcaption></figcaption></figure>


# Software Architectures

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F8zDQUEXpDnmxnbtj7uro%2FSoftware%20Architectures.jpg?alt=media&amp;token=c12ab1ea-64f8-4b78-9dcd-0f7bd8cae477" alt=""><figcaption></figcaption></figure>


# Software Enginering Nuttshell

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FgjRwUkdNfoa07bfaFEDY%2FSoftware%20Enginering%20Nuttshell.jfif?alt=media&amp;token=787fc4ef-5878-4bde-b7cf-ee2572ae9dd2" alt=""><figcaption></figcaption></figure>


# System Desing Interview

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FvZFetUOndBMftevkU2kw%2FSystem%20Desing%20Interview.jfif?alt=media&amp;token=96ae3960-0345-4601-9d26-529efd129c22" alt=""><figcaption></figcaption></figure>


# Type Of Database

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FR5OR9cGVRWU4LVMAyPxy%2FType%20Of%20Database.jfif?alt=media&amp;token=1381c5ad-5ec1-4b7f-855b-1d58eea860f9" alt=""><figcaption></figcaption></figure>


# The Elements of Cloud Pyramid

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FZ6dL3BEHSVGaOCH7u9cV%2FThe%20Elements%20of%20Cloud%20Pyramid.jfif?alt=media&amp;token=40e44965-2ec0-4e6b-a460-dff3607b1cee" alt=""><figcaption></figcaption></figure>


# Top Tools Used in Devops

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FYYL85ryjJiEoeQN98wtX%2FTop%20Tools%20Used%20in%20Devops.jfif?alt=media&amp;token=65d71b05-0db6-4b23-aea1-cd1c1381eace" alt=""><figcaption></figcaption></figure>


# 8 Archtitectural Styles

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FCOWR2hU90xnxoTxc2SbL%2F8%20Archtitectural%20Styles.jfif?alt=media&amp;token=4786876c-bec0-4903-94e6-e51f11fcda6c" alt=""><figcaption></figcaption></figure>


# 7 Step For Api Perfomance

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fb47gJD1I1Qx6QdMz3dhY%2F7%20Step%20For%20Api%20Perfomance.jfif?alt=media&amp;token=dea4a786-9241-45f7-a059-17ee747f8dce" alt=""><figcaption></figcaption></figure>


# 5 Deployment Patern

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fl12SGCIQxD74FnggNLSJ%2F5%20Deployment%20Patern.jfif?alt=media&amp;token=7e67a5c6-a73b-42ac-b94c-299af633ca2e" alt=""><figcaption></figcaption></figure>


# 10 Key Jenkins Pipelines HouseKeeping Routines

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FhEpdqkAQ7fK4y58hz3u5%2F10%20Key%20Jenkins%20Pipelines%20HouseKeeping%20Routines.jfif?alt=media&amp;token=e55191e6-3b8d-4f6a-8b76-b6a9374ef205" alt=""><figcaption></figcaption></figure>


# 12 Cloud Burn Outs

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FVIz4YoeTQsSsxtS5p0Xc%2F12%20Cloud%20Burn%20Outs.jfif?alt=media&amp;token=3c1d9d71-e514-4855-a187-b8b02c9a27df" alt=""><figcaption></figcaption></figure>


# Architecture Netflix

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FfkAvPrl9lVypwtG19xQj%2FArchitecture%20Netflix.jfif?alt=media&amp;token=4c6ab7c7-9091-4094-9e7a-a0f1e6369359" alt=""><figcaption></figcaption></figure>


# ASCII-Table-wide

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F3zDYPWTqiejLDxkaA1Bc%2FASCII-Table-wide.jpg?alt=media&amp;token=8939b036-84ba-4f32-9a88-4ef920d26f4c" alt=""><figcaption></figcaption></figure>


# Aws-Azure-Google-Oracle-Cloud

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FMFFub2A6ZsQNOovkFH8m%2FAws-Azure-Google-Oracle-Cloud.jfif?alt=media&amp;token=9dc3e265-2632-4fa8-ba76-b1ab0d521def" alt=""><figcaption></figcaption></figure>


# Azure Devops

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FS1bdQOrNEZzsUcpf0ZXw%2FAzure%20Devops.gif?alt=media&amp;token=1a3c7624-9dc4-42f2-9472-d4e2b17ae74d" alt=""><figcaption></figcaption></figure>


# Basic Server Types

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FO3j7Pr3WzrbQk23MVMcQ%2FBasic%20Server%20Types.jfif?alt=media&amp;token=2dc4b171-0a0e-46dd-b73e-5093078bb262" alt=""><figcaption></figcaption></figure>


# Cloud Cost Reduction Techniques

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FHjiaAagzACJHA8OP7JuX%2FCloud%20Cost%20Reduction%20Techniques.jpeg?alt=media&amp;token=69c1f6a2-6ae0-47b8-8b7b-36f4db1a17a7" alt=""><figcaption></figcaption></figure>


# Cloud Database Landscape


# What is OSI model

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FrIX6qZ41kTBhq7XuZ4AI%2F1709447151581.jpeg?alt=media&amp;token=2544ada3-0160-483c-bfb8-b68bfd0652e1" alt=""><figcaption></figcaption></figure>


# Chat GPT Prompt

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FLHznkY4XEtDKWAkwIiT5%2F1709413398330.jpeg?alt=media&amp;token=464919dd-998f-4f39-99dc-1dba4b122bc0" alt=""><figcaption></figcaption></figure>


# How does SSO work

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FIdNr3XYmqt8bb0VVFK4r%2F1709448727825.jpeg?alt=media&amp;token=31832142-57e2-481e-ab63-404e1dc98aac" alt=""><figcaption></figcaption></figure>


# How do Message Queues Evolve

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fubx82KKewVH7K6ETduBK%2FHow%20do%20Message%20Queues%20Evolve.gif?alt=media&amp;token=88d45011-a3a1-4166-8edb-71499b74e381" alt=""><figcaption></figcaption></figure>


# API Architectural Styles Comparison

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fe17WD47qtXUZQNjHhl0S%2FAPI%20Architectural%20Styles%20Comparison.jpg?alt=media&amp;token=b42b71e1-700d-46e2-af63-29392b6e109c" alt=""><figcaption></figcaption></figure>


# Cache Systems Every Developer Should Know

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FTAolPh6R4E9x2BeLMmWU%2FCache%20Systems%20Every%20Developer%20Should%20Know.jpg?alt=media&amp;token=dc8f88b8-d5c1-4c17-b8c6-83b39b87fac3" alt=""><figcaption></figcaption></figure>


# Essential DevOps Concepts

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FRE3MJjmuihaHaRrrF4h1%2FEssential%20DevOps%20Concepts.gif?alt=media&amp;token=ce872dc5-3888-4f45-a1c3-6af6f8d8bf44" alt=""><figcaption></figcaption></figure>


# How do C++ Java Python work

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FU4zYoNPgh3Uja7KPdSOe%2FHow-do-c%2B%2B-java-python-work.gif?alt=media&amp;token=f7a2a3d2-bf27-4593-90ee-c0a928c9fff7" alt=""><figcaption></figcaption></figure>


# Top 5 Kafka Use Cases

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F25n4AEm57MF6UVUyhcNC%2FTop%205%20Kafka%20Use%20Cases.jpg?alt=media&amp;token=5b420e10-584e-4149-99a4-e33abc670607" alt=""><figcaption></figcaption></figure>


# Why is Kafka Fast

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FBbH8f7vddSiq1rkM5fdT%2FWhy%20is%20Kafka%20Fast.jpg?alt=media&amp;token=d9b89044-381d-47d6-8c77-b29d7c899776" alt=""><figcaption></figcaption></figure>


# 10 QUESTIONS quality of decision making

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FjNQq511KO2lz5HSllVn8%2F10%20QUESTIONS%20quality%20of%20decision%20making.jpeg?alt=media&amp;token=b801e3a3-f42b-4add-8250-0ef9b82cce2f" alt=""><figcaption></figcaption></figure>


# End to End Software Development Life Cycle

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fz2FWKVU8YDhfFsTxodDz%2FEnd-to-End-Software-Development-Life-Cycle.gif?alt=media&amp;token=0594d0fa-83ec-4dd8-9e58-96f7efa19127" alt=""><figcaption></figcaption></figure>


# Networking Crash Course

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fvmq6MCxWF3WL19RFlhUJ%2FNetworking-Crash-Course.gif?alt=media&amp;token=6a8fd56b-2945-4817-89d9-0af80d9d53aa" alt=""><figcaption></figcaption></figure>


# What is Observability

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FQBv5JH5kDvsQo9TrC0XD%2FWhat%20is%20Observability.gif?alt=media&amp;token=d9690b10-963c-4c4c-8477-41f26ebfef3a" alt=""><figcaption></figcaption></figure>


# Rest vs GraphQL

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FjF6UQdmjDY6z5Vk6NnN0%2FRest-vs-GraphQL.gif?alt=media&amp;token=0be76bcf-2a34-47ad-bc52-4f77a514a39a" alt=""><figcaption></figcaption></figure>


# Statefull Set

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FenD1hYcvalr1u8568bUw%2FStatefull%20Set.jpeg?alt=media&amp;token=547b4b3c-6f46-4b8a-ae12-311b024301e4" alt=""><figcaption></figcaption></figure>


# System Design Cheat Sheet

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F7oC1QJab1wVyUjEEPPe9%2FSystem%20Design%20Cheat%20Sheet.gif?alt=media&amp;token=029cb157-2658-44e9-84e2-14008d506257" alt=""><figcaption></figcaption></figure>


# MeMes


# Github

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FPbcpSnHfXrLLZKS9MRqX%2Fgithub.jpg?alt=media&amp;token=db2f35f4-00d3-4b57-ac4d-8675e50a9432" alt=""><figcaption></figcaption></figure>


# Continers

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Ff9JOKwsRQKyKhAzZ9W7T%2FContiners.jpeg?alt=media&amp;token=d8eea672-fa18-4e99-a599-a0f4101336ce" alt=""><figcaption></figcaption></figure>


# What Gives People Feelinfs

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F1cN6kliiyZEtpdr0PVR5%2FWhat%20Gives%20People%20Feelinfs.webp?alt=media&amp;token=f35d25da-31ce-46c7-943e-1a9c875fe3f3" alt=""><figcaption></figcaption></figure>


# Kubernetes Solve Problem

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fv0TKLL0ZBEvxhO5fnwDP%2FKubernetes%20Solve%20Problem.webp?alt=media&amp;token=12afbe7a-bb57-4c6f-8e27-09f9e30c21a1" alt=""><figcaption></figcaption></figure>


# Kubernetes Update

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2F7uWKDTf1XCZEyS54pTJ6%2FKubernetes%20Update.jpg?alt=media&amp;token=450c6c87-6158-4a2d-8f23-7acf32c50201" alt=""><figcaption></figcaption></figure>


# Docker Inc. 2014

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FSBmTo650YAuirTa4o5US%2FDocker%20Inc.%202014.png?alt=media&amp;token=c926b268-6d7e-4306-a7c3-414f5fdfb0fd" alt=""><figcaption></figcaption></figure>


# DevOps Before After

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FhGeIqHFrGwV8H0UOeyol%2FDevOps%20Before%20After.png?alt=media&amp;token=7e7bc472-710d-42b5-b6d2-42938fec7368" alt=""><figcaption></figcaption></figure>


# Kubernetes Real Life

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2Fe3plZ8zGBAskXryUAduJ%2FKubernetes%20Real%20Life.jpeg?alt=media&amp;token=91f27f40-7207-4974-ac03-9eda22f994c9" alt=""><figcaption></figcaption></figure>


# Kubernetes Solve Problem

<figure><img src="https://1041106579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FctwsWVHhTx4xf0lm1noh%2Fuploads%2FVhfL06mJkFxczE474jqW%2FKubernetes%20Solve%20Problem.webp?alt=media&amp;token=88f91e06-7d68-4193-be0b-adec55b3591c" alt=""><figcaption></figcaption></figure>


# Cloud Provider


# Cloud Servis Sağlaycılar

İlk olarak Kubernetes için gerekli olan cloud bilglieri özellikle klısaltma ve tanımlamarını aşağıdaki gibidir.

resim gelecek

<mark style="background-color:red;">EKS:</mark> Elastic Kubernetes Services: Amazon Web Services’ Elastic Kubernetes Services <https://github.com/AdminTurnedDevOps/Kubernetes-Quickstart-Environments/tree/main/aws>

<mark style="background-color:red;">AKS:</mark> Azure Kubernetes Service: Microsoft Azure Kubernetes Service <https://github.com/AdminTurnedDevOps/Kubernetes-Quickstart-Environments/tree/main/azure>

<mark style="background-color:red;">GKE:</mark> Google Kubernetes Engine: Google Cloud Platform Kubernetes Engine <https://github.com/AdminTurnedDevOps/Kubernetes-Quickstart-Environments/tree/main/Google>


# Kim ne  hizmet sunuyor.

En çok bilinen amazon, azure ve google cloud platformlarından bir çok servis var ve her cloud hizmet sağlayıcı bunları farklı isimler ve yapılarda sunuyor, ve bu durumda süreçler şöyle işliyor sürekli yeni hizmetler ekleniyor, bu yüzden takipte biraz zorlaşıyor, bu süreçleri durumları kolayca karşılaştırıp hangi servis hangi servis sağlayıcıda neydi diyebilmek ve takip edebilmek için güzel bir site adresi :thumbsup: <https://comparecloud.in/> buradan bir çok hizmeti ve erişim linkini bulabilirsiniz. Çok güzel bir himzet bence.

buradaki cloud servis sağlayıcılar ise;

* [aws](https://aws.amazon.com/tr/)
* [azure](https://azure.microsoft.com/tr-tr)
* [google cloud](https://cloud.google.com/)
* [ibm cloud](https://www.ibm.com/cloud)
* [oracle cloud](https://www.oracle.com/cloud/)
* [alibaba cloud](https://www.alibabacloud.com/tr)
* [huawei cloud](https://cloud.huawei.com/)


# CNCF


# CNCF

Ne bu " CNCF "  kısaca Cluud Native Computing Foundation.

Open soruce dünyasında Colud Native uyghulamar için bir çatı organizasyonu diyebiliriz. En büyük destekçisi google bir çok firma var burada doğan büyüyen ve canlı ortamlarda kullanılmaya başlayan bir çok ürün var, Belki Türkiyed' ki Tekonkent' lerdeki yapı CNCF i önreklemek için kullanılabilir. CNCF kuluçka merkezi olarka düşünürsek DEVOPS ve OpenSopurce dünyaya katıkıda bulunan bir çok alandaki bir çok yazılıma gelişim ve büyüme şansı tanıyan dernek organizason diyebiliriz.

web sitesi : [www.cncf.io](https://devops.1w2.net/cncf/www.cncf.io)&#x20;

CNCF içinde olan bütün projeleri[ şu adresten](https://landscape.cncf.io/?category=provisioning\&grouping=category) kontrol edebilirsiniz. Burada bir çok farklı kategordie ürün mevcut CNCF tarafından destekelenen ürünler burada aryıca mezun olmuş yani prod ortama geçiş sağlamış yazılımlarda burada daha gelişmekte olanlarda bu listede.




---

[Next Page](/llms-full.txt/1)

