Mikroservis Mimaride İletişim
Mimari evrimi monolitic uygulamalardan SOA’ya, SOA’dan da mikroservis mimarisine kadar geldi. Mikroservis mimarisi, servislerin olabildiğince küçük, yalnıza kendi işini yapan atomik her birinin kendi veritabanına sahip servislere ayrılmasıyla inşaa edilen dağıtık bir mimari yapıdır. Burada ufak dağıtık servislerden oluşturulan yapı cümlesi önemlidir. Çünkü dağıtık yapıların, sadece mikroservisler değil her ne konseptte oluşturuluyor olursa olsun konularından biri de dağıtık yapılar arasındaki iletişimin nasıl sağlanacağıdır ki çok geniş kapsamlı bir konudur. Bu yazımda dağıtık mimarilerdeki iletişimi mikroservisler üzerindeki özel çözüm yaklaşımları üzerinden anlatmaya çalışacağım.
1. Synchronous Communication
Senkron iletişim, bir servisten diğerine bir istek attığımız zaman, ilgili servisin bu isteği işleyip geriye sonuç dönene kadar ki süreyi bekleyip sonucu alıp yola devam edilen iletişim şeklidir. Yani client bir servise request atar. Bekler. Responseunu alır. Yoluna devam eder. Response gelene kadar thread blocklanır. Dolayısıyla iletişim kuran iki tarafında ayakta olması gerekir. Bu da haliyle ciddi performans problemlerini ortaya çıkarabilir.
1.1 Request Driven Communication
Request driven communication aslında iyi bildiğimiz, implementasyonu basit olan communication şeklidir. Servisler birbirleri ile HTTP istekleri (post, get, put, delete) ile haberleşirler. Yani bir data alışverişi ya da herhangi bir sebepten iletişim ihtiyacı olduğunda bir servis bir diğer servise request atar, arkasından o servisten response bekler ya da ihtiyaç yoksa beklemeden devam eder.
Ancak burada üzerine düşünülmesi gereken bazı durumlar vardır.
Latency : Aslında bu kısım senkron iletişimin tanımıyla aynıdır. Client ilgili servise request atar ve responseunu bekler. İlgili servis bu requesti alır. Yapacağı işleme göre işlemeye başlar ve client da bu süre boyunca bekler yani clientin threadi blocklanır. Bu da istenen bir durum değildir.
Network Trafiği : Mikroservis mimarisindeki servislerin her biri, doğası gereği sadece kendi işini yapmaya odaklanmış, küçük ve atomik servislerdir yani mikroservis mimarisinde SOA’ya kıyasla daha fazla atomik servisiniz olur. Servisler arası iletişim ihtiyacınız daha fazla dolayısıyla request/response trafiğiniz de fazla olur ki bunun yönetimi de ayrı bir konudur. Log servisi servise çevirmeyin.
Loose/Tight Coupling : Servisler birbirleri ile iletişim kuracaklarsa, bir şekilde birbirlerine ihtiyaç duyuyorlar demektir. Bu durumda aklımıza ilk gelecek kavramlardan birisi de coupling olmalı. Servislerimizin birbirleriyle iletişimini sağlarken kullandığımız yöntem bize loose coupling sunuyor olmalı yani servisler birbirine sıkı sıkıya bağlı olmamalı. Bir serviste yaptığınız değişiklik direkt olarak bir diğerini etkilemiyor olmalı. Request driven communicationda servisler direkt olarak birbirleriyle iletişimde olduğundan tight coupling bir iletişimden bahsedebilir.
Referencially Coupling : Ayrıca bir başka konsept olan referencially coupling’e de burada değinmemiz gerekir. Birbiriyle iletişimde olan servisler birbirleri hakkında referans bilgisine sahip olmak zorunda ise buna referancially coupled diyebiliriz. Yani daha basit bir deyişle, bir servis başka bir servisle iletişime geçmek için diğer servisin locationunu, end pointini bilmek zorundaysa servisler birbirlerine referancillly coupledtır.
Temporally Coupling : Temporally coupling kavramı en basit anlatımıyla, birbiriyle iletişimde olan iki sistemin iletişimi gerçekleştirmek için aynı anda ayakta olması ihtiyacı demektir. Request driven mimariler genelde temporal coupledtır. Yani bir servisin diğerine request gönderip responseu alması sürecinde iki tarafında ayakta olması gerekir.
Fault Tolerance System : Bir diğer önemli konu da birbirleriyle iletişimde olan servislerden birinin çökmesi durumunda iletişimin ne olacağıdır. Request driven communicationda servisler birbirleri ile http istekleriyle haberleştikleri için herhangi bir servisin çökmesi durumunda bir servis diğer servise call yapamayacak ve iletişim o servis ayağa kalkana kadar duracaktır.
2. Asynchoronous Communication
Senkron iletişimde akla gelen soru bizim clientimiz ya da bir başka servisimizdeki herhangi bir istek sonucunu beklemek zorunda mı? Request attıktan sonra sonuç işlenmeden geri kalan işlerine devam etse, sonuç geldiğinde sonucu alıp işlese daha performanslı olmaz mı? Asenkron iletişimde ise aslında bahsettiğimiz gibi, request atıldığında servisten cevabın dönmesi beklenmeden clientın işlerine devam ettiği ve response hazır olduğunda aldığı iletişim yapısıdır. Dolayısıyla asenkron iletişim communication latencysi de düşürür. Haliyle bu da bize oldukça performans kazandırır. Buradaki anahtar nokta client threadinin response dönene kadar blocklanmamasdır.
2.1. Event Based Mimari
Bir diğer communication şekli event-based mimaridir. Adından da anlaşılacağı üzere, decoupled servisler arasındaki iletişimi event fırlatarak trigger eder. Event dediğimiz de aslında bir stateteki değişim ya da güncelleme gibi düşünebiliriz.
Event based mimarilerin üç temel bileşeni vardır: Producers, event routers ve cosumers. Bir producers, event routera, consumerlar tarafından consume edilmek üzere bir event pusblish eder. Producer servisleri ve Consumer servisleri birbirlerinden bağımsız olarak ölçeklendirilmelerine, güncellenmelerine ve dağıtılmalarına olanak tanıyacak şekilde ayrıştırılmıştır. Event bir messaging queue üzerinden sıraya girer ve yerine ulaşır. Genelde Event Based mimariler Pub/Sub modelini kullanırlar. Sistemde Producer ve Consumerlar vardır. Producer bir event publish eder ve bu procudure’a subcribe olan consumerlar bu eventi alırlar. Dolasıyla servisler arasında direkt olarak bağımlılık yoktur. İletişimimiz asenkron olacağı için performans kazanımı sağlar.
Tüm servisler bir messaging queue üzerinden iletişim kurarlar. Bu da yukarıda da bahsettiğimiz couplingin loosely olmasını sağlar. Bunun yanında birbirleriyle iletişimde olan 2 servisten birinin çökmesi durumunda, diğer servisten ilgili servise giden request eventler, servis çökmüş olsa bile queueda bekler ve ilgili servis ayağa kalktığında işlenir.
Latency : Event based mimariler asenktron yapıda olduklarından, event fırlatıldığı ya da consume edildiği sırada latency yoktur.
Network Trafiği : Event based mimariler yuakrıda da bahsettiğim gibi push based çalışırlar. Bu, daha az ağ bant genişliği tüketimi, daha az CPU kullanımı, daha az SSL / TLS anlaşması anlamına gelir.
Loose/Tight Coupling : Event based olarak kurgulanan dağıtık bir yapıda, servisler tamamen loose coupling olarak kurgulanmıştır. Bir servis diğer servisin varlığından haberdar bile değildir. Yalnızca event routerın, queuenın varlığından haberdardırlar.
Referencially Coupling : Event based mimari ile kurgulanan dağıtık yapılar bir önceki maddede de bahsettiğim gibi, birbirlerinden değil yalnızca merkezde bulunan queuedan haberdardırlar dolayısıyla birbirleriyle ilgili bir referans end point vs bilgisine ihtiyaç duymazlar. Bu sebeple referencially decoupled yapıdadır diyebiliriz.
Temporally Coupling : Aslında temporally coupling kavramı bir derece fault tolerance ile ilişkilidir. Event based mimarilerde consumer servis bir sebepten down olduğunda, consume etmesi gereken event queueda bekler. Ne zaman ki down olan servis tekrar ayağa kalkar, event consume edilebilir. Dolayısıyla event base kurgulanan mimari için temporally decoupled diyebiliriz.
Fault Tolerance System : Temporally coupling konseptinde de bahsettiğim gibi, eğer servislerden biri down olursa eventler queueda durmaya devam eder ve her nezaman down olan servis ayağa kalkar sistem kaldığı yerden işlemeye devam eder.
Bir mikroservis mimarisi kurguladığınız zaman, her yaklaşımın avantajları ve dezavantajları vardır. Örneğin, low amount bir transaction ile çalışıyorsanız, event messaging mimarisi kurgulamak maliyetli olabilir. Hızlıca rest request/response yaklaşımıyla ilerleyebiliriz. Ancak transaction oranı arttıkça sıkıntılar baş göstermeye başlar.