Nedir bu Mikro Servisler (Microservices) ?

Merhaba,

Son dönem çok defa ismini duyduğumuz, neredeyse herkesin ya yeni uygulama geliştirmeye başlarken ya da mevcut uygulamalarını bu yapıya güncellemek için düşüncelere daldığı mikro servis konusunu inceleyeceğiz. Öncelikle mevcut durumun ardından mikro servis konusunu inceledikten sonra API Gateway modeli üzerinden bir örneklendirme yapacağız.

O zaman ? Buyursunlar.

Mikro Servis Yapısı Hakkında

Monolitik Mimari Yapılar
Mikro servislerden bahsetmeden önce biraz mikro servis öncesi durumları incelemek yararlı olacak diye düşünüyorum. Nereden ? Nereye ? Büyük ihtimalle şimdiye kadar hatta şu an bile geliştirdiğimiz uygulamalar monolit yapıdaki uygulamalar. (Benim öyle şu an) Peki nedir bu monolitik yapı?

Monolitik mimari geniş bir kitle tarafından kullanılan geleneksel bir mimari aslında. Geliştirdiğimiz uygulamanın tüm parçalarının aynı proje içinde olması diyebiliriz. Peki, biz zaten gevşek bağlanmış (loosely coupled) uygulamalar geliştiriyoruz. Monolitik mimari burada neyi değiştiriyor diyebilirsiniz. Açıklamaya çalışayım efendim.

Uygulama içerisinde kullandığımız tüm bileşenlerimiz birbirleri ile gevşek bağlı olabilir fakat uygulamamızın içerisinde bulunan her şey uygulamanın kendisi ile sıkı sıkıya bağlı durumda. Bunun en güzel örneği dağıtım (deployment) aşamasında karşımıza çıkıyor. Eğer biz uygulamamız içerisinde bir güncelleme yaparsak ve bunu üretim (production) ortamında yayınlamak istersek o zaman tüm uygulamayı baştan yayınlama aşamasına göndermemiz gerekiyor. Aynı durum üretim ortamında çalışan uygulamalarımızda oluşan sorunlar karşısında da ortaya çıkıyor.

Örnek vermek gerekirse bir bankacılık uygulaması içerisinde kullanıcıların varlıkları ile ilgili işlemler yapılıyor. Hesap bilgileri, kredi kartı bilgileri, yatırım bilgileri vb. Eğer kart işlemleri modülü ile ilgili bir hata oluşursa uygulamamız kartların bilgileri çekerken hata alacak durumda.

“Ne var? O noktada hata alırsa bir yolla hatayı fırlatmaz log olarak sisteme yazabilirim. Veya yumuşak bir geçiş ile kullanıcının mutluluğunu bozmam.” Evet olası bir durum, yapılabilir fakat ne kadar doğru? Tabii uygulamamız için yapacağımız yeni geliştirmelerde de bu sorun mevcut. Kart ekstreleri ile ilgili bir geliştirme yaptınız. Bunun üretim ortamına çıkması gerekiyor. O zaman tüm uygulamanın üretim ortamına alınması, hatta farklı yerlerin etkilenip / etkilenmediği kontrolleri vs. vs. Sadece kart modülü için yapılan bir değişiklik için sizi uzun bir yolculuk bekliyor aslında.

Mikro Servis Mimarisi
Bu mimaride uygulamamızı her birinin farklı bir hizmet verdiği bileşenlere ayırıyoruz. Her bileşen ayrı bir uygulama olarak yaşam döngüsünü sürdürüyor. Bankacılık uygulaması örneğimize geri dönecek olursak hesaplar, kartlar ve yatırım ürünlerinin ayrı birer küçük uygulama olduklarını düşünelim. Bu küçük uygulamalara bölmenin bize kattıkları konusunu inceleyelim.

Hesap bilgilerini dönen servisimiz gayet güzel çalışırken, kartları dönen servisimizde bir hata olması durumunda sistemin geneli etkilenmeden akışlarımız devam edebilir.

Bu küçük uygulamalardan herhangi birinde bir yük artışı olduğu zaman (küçük olmalarından dolayı) hızlı bir şekilde yatay olarak ölçeklendirilebilir. (horizontal scale). Daha sonrasında eğer yük azalırsa ölçeklendirme sonucunda oluşan yeni makinelerin kapatılması da söz konusu. (Docker ve Kubernetes)

Yine, bu küçük uygulamalardan herhangi birinde yapacağımız bir kod güncellemesini diğer uygulamalar etkilenmeden üretim ortamına alabilme yeteneğimiz de oluyor.

O zaman genel olarak baktığımız zaman mikro servis mimarisi, uygulamanın kendisinin çeşitli bileşenlere bölündüğü ve her bileşenin belirli bir amaca hizmet ettiği bir mimaridir. Bileşenler artık uygulamanın kendisine bağımlı değildir. Bu bileşenlerin her biri tam anlamıyla ve fiziksel olarak bağımsızdır. Bu şekilde kurulmuş olan bir mimari ile uygulamalarımız ayrı ayrı veri tabanlarına sahip olabildikleri gibi ayrı makinelerde de barındırılabilirler.

Avantajları

  • Mikro servislerin her biri ayrı uygulama olarak çalıştıklarından dolayı ayrı programlama dili ile de yazılabilir.
  • Ekibe yeni katılan bir geliştiricinin (developer) tüm yapıya hakim olması için geçecek olan zamanı azaltarak belirli mikro servisler üzerinde hızlı bir şekilde çalışmaya başlaması sağlanabilir.
  • Dağıtım (deployment) aşaması her mikro servis için ayrı ayrı yapılabilir. Bu da deploy sürelerini kısaltmış olur.
  • Mikro servislerin çalıştıkları konteynır (container) üzerinde yüke göre ölçeklendirme uygulanabilir.
  • İstenildiği zaman farklı veri tabanlarında çalışacak mikro servisler geliştirilecek yapıya dahil edilebilir. Örnek olarak MongoDb ile çalışacak ve Go ile yazılmış bir mikro servisi de yapınıza sonradan dahil edebilir ve ortak çalışma alanında bu mikro servis üzerinden faydalanabilirsiniz.

Dezavantajları

  • Transaction bütünlüğünün sağlanmasındaki zorluklar.
  • Servisler arası iletişim ve bütünlük zorlayıcıdır.
  • Integration testlerin hazırlanması zordur.
  • Genel olarak iş mantığına iyi derecede hakim olmamız gerekmektedir.
  • Dağıtım (deployment) sonrası kontrol, güvenlik ve yönetim işlemlerinin iyi bir şekilde yapılması gerekmektedir. Servis sayımız çoğaldıkça bu konularda da zorluklar ortaya çıkmaktadır.

Şimdi de ufak bir mikro servis örneği ile devam edelim. Bu çalışmada bir yazar ve bir kitap servisimiz olacak. Bu servislerimiz bize sadece kendi konuları ile ilgili bilgileri verecekler.

Burada bir soru işareti ortaya çıkıyor. Bu servisleri çağıracak olan client hepsinin adresini bilmesi mi gerekiyor? Hayır, buna gerek yok. Biz bir API Gateway ekleyerek client uygulamanın bu adrese gelmesini sağlayacağız. Client API gateway üzerinden hangi işlemi isterse gateway bizim için yönlendirme (routing) işlemini yapacak ve uygun servis cevaplarını dönecek. Bunun için Ocelot kütüphanesini kullanacağız.

İlk olarak yeni bir boş çözüm (blank solution) oluşturarak ismin MyMicroServices vererek projemize başlıyoruz.

Oluşturacağımız mikro servisleri ayırabilmek için MicroServices isimli bir klasör oluşturuyoruz.

Şimdi oluşturduğumuz klasörümüze iki adet ASP.NET Core Web API projesi oluşturacağız. İsimlerini Author.Microservice ve Book.Microservice olarak vereceğiz.

Son olarak da API Gateway olarak görevlendireceğimiz MyGateWay.WebApi isimli projemizi oluşturacağız. Bu projemizi ASP.NET Core Empty proje temasını (template) kullanarak oluşturuyoruz.

Son durumda projemin yapısı aşağıdaki gibi olacaktır.

Author.Microservice isimli projeme Entities isminde bir klasör ekleyerek AuthorInformation.cs isimli sınıfımı (class) ekliyorum.

Ardından Controllers klasörüne AuthorController isminde API Controller sınıfımızı ekleyerek bize yazar listesi döndürecek olan metodumuzu ekliyoruz.

Postman üzerinden API metodumuzu test ettiğimiz zaman aşağıdaki şekilde bilgileri döndürdüğünü görebiliriz.

Aynı şekilde Book.Microservice uygulaması içinde bir Entities klasörü açarak BookInformation.cs sınıfını ekleyeceğiz. Ardından Controllers klasörüne BookController.cs sınıfımızı ekleyerek kitap bilgilerini dönecek metodu yazacağız.

Ocelot API Gateway hakkında biraz daha
Ocelot open source olarak dağıtılan .NET/Core platformları için geliştirilmiş bir API Gateway ürünüdür. Arkasında bulunan mikro servislerin adreslerini bir konfigürasyon dosyasına kayıt ederek gelen isteğin hangi mikro servise gitmesi gerektiğini tanımlayacağız. Böylelikle client bir istekte bulunduğu cama Ocelot bizim için yönlendirmeyi yapacak ve uygun cevabı dönecek.

Konfigürasyon dosyası json formatındadır. Burada rotalarımızı (route) tanımlarken karşımıza iki terim çıkıyor. Bunlar; UpStream ve DownStream UpStream client’ın geleceği adresi tarif ederken DownStream ise Ocelot’un çağıracağı iç servis bilgisini tanımlamaktadır.

Ocelot API Gateway olarak servislerin rotalarının oluşturulması haricinde kimlik doğrulama (Authentication), yetki (Authorization) ve yük dengeleme (Load Balance) işlemlerini de bizim için yapabilmektedir.

MyGateWay.WebApi projesine Ocelot paketini ekliyoruz. Bunun için isterseniz Install-Package Ocelot komutunu isterseniz de Nuget Packet Manager üzerinden paketin yüklemesini yapabilirsiniz.

Daha sonrasında Program.cs sınıfımız içerisinde aşağıdaki değişikliği yapıyoruz.

Buradaki amacımız uygulamamızın açılışında ocelot.json isimli dosya içerisinden Ocelot konfigürasyon bilgilerinin alınması.

Şimdi de Startup.cs isimlii sınıfın içerisinde bulunan ConfigureServices metoduna Ocelot’u ekleyelim. Ardından yine aynı sınıf içinde bulunan Configure metodunda da Ocelot kullanımı için tanım yapacağız.

Şimdi de sıra Ocelot üzerinde rota bilgilerini tanımlama kısmına geldi. Öncelikle burada iki adet mikro servisin hangi portlar üzerinden çalıştığının kontrol etmemiz. Daha sonrasında ise VS üzerinden uygulamalardan birini çalıştırdığımız zaman hepsinin ayağa kalkması için bir değişiklik yapmamız gerekecek.

Önce servis portları. Bunun için Author.Microservice ve Book.Microservice projelerine tek tek sağ tuşal tıklayarak açılan Properties penceresinde sol bölümde bulunan Debug menüsünü açıyoruz. Port bilgisi sayfa üzerinde gelecektir.

Burada port bilgisini Book.Microservice için 1360 Author.Microservice için 1361 olarak değiştiriyoruz. Bu değişikliği isterseniz projelerin her birinde bulunan launchSettings.json dosyası üzerinden de yapmanız mümkün.

Uygulamaların hepsinin aynı anda çalıştırılması için Solution Explorer üzerinden Solution dosyasına sağ tuşla tıklayarak Properties menüsü üzerinden açılan sayfada değişiklikleri aşağıdaki gibi yapabilirsiniz.

Şimdi Ocelot üzerinde rota tanımlarımızı yapabiliriz. Bunun için daha önceden tanımını yaptığımız ocelot.json isimli dosyayı MyGateway.WebApi projemizin root’una tanımlıyoruz. Ardından aşağıdaki şekilde rota (route) tanımlarının yapıyoruz.

Burada yaptığımız tanımlamaları biraz açıklamak gerekiyor.

Routes altında tanımladığımız;

DownstreamPathTemplate: Ocelot’un gideceği API rotası olarak açıklanabilir. 
DownstreamScheme: http olarak veya https olarak gidileceğinin tanımı. 
DownstreamHostAndPorts: Author servisi için kullanılacak olan Ocelot arkasındaki adres bilgisi.

UpstreamPathTemplate: Client uygulamanın gateway’e geleceği API rota bilgisi. 
UpstreamHttpMethod: Client uygulamanın hangi HTTP Verb için bu adrese geleceğini tanımladığımız yerdir.

Ardından tanımlarımızı ve servislerimizi test edebiliriz. Daha önceden Project Properties penceresinden tüm uygulamalar beraber çalışmaya başlasın dediğimiz için F5 dememiz servislerin hepsinin çalışması için yeterli olacaktır.

Eğer pencere üzerinden bir değişiklik yapmadıysanız hepsini tek tek çalıştırmanız gerekmektedir.

Postman ile API Gateway uygulamamıza hem kitaplar hem de yazarlar için çağrılarımızı yapalım. Bakalım nasıl bir bilgi gelecek.

Gördüğünüz gibi hem http://localhost:5000/gateway/Book hem de http://localhost:5000/gateway/Author adresleri API Gateway uygulamamız içerinden çağırılan adresler. Bu adresleri Postman uygulaması ile çağırdığımız zaman Ocelot bizim için uygun olan servise gidiyor ve o servis sonucu alarak bize geri iletiyor.

Böylelikle client’ın hangi servisi nasıl çağırması gerektiğini bilmesine gerek kalmıyor. Client sadece API Gateway adresini biliyor ve oraya geliyor.

Umarım mikro servis mimarileri ve temel çalışma prensiplerini anlama konusunda yararlı bir makale olmuştur.

Görüşmek üzere…

Kaynaklar:

http://mustafabas.me/tr/mikroservis-mimarisi-nedir-avantajlari-dezavantajlari-nelerdir–b-1006

Microservice Architecture in ASP.NET Core with API Gateway