Mikroservis Yaklaşımında Servisler Arası İletişim Mimarileri

Mikroservis mimarisi üzerine çalışıyorsanız karşılaşacağınız en önemli problemlerden bir tanesi; geliştirilen mikroservisler arasındaki iletişim mimarisini kurgulamaktır. Monolitik ve *SOA mimaride geliştirilen uygulamalarda servisler arası iletişim gibi bir problem ihtiyacı genellikle yoktur, ihtiyaç olduğu durumlarda ise http request’ler veya internal event’ler ile kolaylıkla çözülebilmektedir.

Bu yazıda mikroservis mimaride iletişim yöntemlerini, örnek olarak tasarlayacağımız bir rezervasyon platformu ile öğreneceğiz. Bu platformun sahip olması gereken temel servisleri belirleyecek ve bu servisler arası iletişimin nasıl yapılabileceğini örnek senaryolar ile öğreneceğiz.

Mikroservisimizi Tasarlayalım

En temel işlevlere sahip bir rezervasyon platformu yapalım, örneğin; booking.com benzeri olsun. Kullanıcımızın bir oda rezervasyonu yapabilmesi için akla gelen ilk servisler oda seçimi, ödeme ve bilgilendirmedir.

Check-in (Odayı Seçmek ve Süreci Başlatmak), Payment (Ödemeyi Yapabilmek) ve Information (Müşteriyi Bilgilendirebilmek) mikro servislerimiz olsun. Uygulamamızı kullanan müşteri bir oda kiralamak istediğinde aşağıdaki adımlar izlenecek. Bu adımlar;

  • Kullanıcı, Check-in servisi ile odasını ve giriş çıkış tarihini belirleyecek.
  • Belirlenen odaya ve giriş çıkış tarihine göre ödeme işlemi gerçekleştirilecek.
  • Kullanıcıya, rezervasyon kaydının alındığını bildiren bir email gönderilecek.

 

Mikroservisler: Check-in , Payment ve Information

Servisler Arası İletişim

Uygulamamızın ne yapması gerektiğini belirledik, kullanıcı uygulamamız aracılığıyla rezervasyon için kayıt oluşturduğunda, uygulama (Web sitesi veya mobil uygulama) ilk olarak, Check-in servisinin doCheckin endpoint’ine bir post request yapacak. Check-in servisi gelen isteği değerlendirecek, kendi iş kuralları her neyse onları işletecek ve rezervasyon listesine kaydı ekleyecek. Bu süreçte kullanıcının kredi kartı bilgilerini kullanarak rezervasyon için gerekli ücretin tahsil edilmesi ve kullanıcının bilgilendirilmesi gerekecektir.

Monolitik bir uygulamamız olsaydı tüm bu süreçleri aynı uygulama içerisinde, event fırlatarak, request atarak ve pub/sub gibi yöntemlerle rahatlıkla işletebilirdik. Mikroservis mimarisinde ise işleri yapan servisler bir birinden bağımsız olarak konumlandırıldığı için süreçlerin senkron (synchronous) veya asenkron (asynchronous) işletilebilmesi için farklı mimari yaklaşımlara başvurcağız.

1. Mesaj Kuyruğu (Message Queues) ile Olay Güdümlü Mimari (Event Driven Architecture)

Mesaj kuyruğu yaklaşımı, mikroservis mimarisine özel bir yaklaşım değildir, monolitik uygulamalarda bile sık sık tercih edilen bir yöntemdir. Bu yaklaşım, mikroservisler arası haberleşme yöntemi olarak kullanıldığında, genellikle event driven mimari kurgulamak için tercih edilir.

Event Driven mimari, bir birleriyle haberleşmesi gereken servislerin dağıtık sistemde, event fırlatarak ve bu event’i handle ederek süreci tamamlayabilmesini amaçlamaktadır. Servisler arası event’ler merkezi bir Event Bus ile gerçekleştirilir. Bu mimarideki event bus aracı olarak message queue’lar tercih edilirler. Servislerin bu bus’a pub/sub ile bağlı kalarak her bir event fırlatıldığında haberdar olması ve handle edebilmesi sağlanır. Tüm event trafiği bu bus üzerinden geçecektir.

 

Message Queues ile Event Driven Mimari

Daha önce servislerimizi belirlemiştik, doCheckin servisi gelen request’i işlerken asenkron olarak payment servisini bilgilendirmeli bir event fırlatmalıdır (1 numaralı bağlantı) bu event ile birlikte payment için gerekli bilgileri göndererek doPayment adımının da başlatılmasını sağlamalıdır (2 numaralı bağlantı). İki servis işlemini gerçekleştirdiğinde süreç hakkında kullanıcıyı bilgilendirmek için ikiside bir completed event’i (3 ve 4 numaralı bağlantılar) fırlatmalı ve information servisinin sürecinin başarı ile tamamlandığından haberdar olması sağlanmalıdır.

Event Driven mimari kullanmak istediğinizde çok fazla event driven implementasyonu bulabilirsiniz. Lightweight çözüm arıyorsanız RabbitMQ tercih edebilir, cloud ortamında ise neredeyse tüm üreticilerin sahip olduğu farklı mesaj kuyruğu teknolojilerini kullanılabilir.

Bu mimaride dikkat edilmesi gereken nokta; sistemin Event Bus’a bağımlı olmasıdır. Event Bus’da meydana gelecek bir kesinti durumunda, transaction bütünlüğü kaybolabilir ve servisler arası iletişim kopabilir.
Event driven mimariyi kurgularken farklı pattern’lardan da yararlanabilirsiniz. Örneğin, SAGA veya yaygın kullanımı olan Event Sourcing paternleri incelenebilir. Bu konuda Martin Fowler’ın What do you mean by “Event-Driven”? başlıklı yazısına da göz atabilirsiniz.

2. İstek Tabanlı Mimari (Request Driven Architecture)

Request driven mimari kullanması ve tasarlaması belkide en kolay yöntemlerden bir tanesidir. Bu mimari farklı teknolojiler kullanılarak tasarlanılabilir, örneğin Rest veya RPC (Remote Procedure Call).
Bu mimaride rest tercih edildiğinde, servisler; doCheckin, doPayment ve sendMail şeklinde end point’lere sahip olurlar. Bir birleriyle haberleşirken bu end-point’lere http istekleri (GET, POST, PUT, DELETE) yapılır.

RPC ile bir mimari kullanıldığında Google tarafından geliştirilen gRPC’tercih edilmektedir. Bu teknoloji ile birlikte rest tarafından kullanılan JSON veya XML dosyaları yerine protobuf (Protocol Buffers) kullanılır. Protobuf dosyaları serialization/deserialization edilebilir bu sayede veri trafiği binary olarak gerçekleştirilebilir.

İstek Tabanlı Mimari (Request Driven Architecture)

Teknoloji olarak ele aldığımızda, ister Rest ister SOAP istersenizde RPC kullanın mimari tasarım yukarıdaki gibi olacaktır.

Senaryomuzda, kullanıcı isteğini karşılayan ilk servis (Check-in mikroservisi) orchestrator görevi görebilir yani transaction sürecini yönetir. Servise gelen istek, validasyonlardan ve iş kurallarından geçtikten sonra, asenkron olarak payment servisine bir istek yapar (3 numaralı bağlantı), eğerki payment işlemi ile birlikte başka bir süreç işletmek istiyorsa, yine asenkron olarak ilgili servise çağrıda bulunur (4 numaralı bağlantı).

3. Mesaj Tabanlı Mimari (Message Driven Architecture)

Mikroservisler arası iletişim mimarilerine baktığınızda bir diğer yaklaşım ise Mesaj Güdümlü İletişim (Mesaj Message Driven Communication) mimarisidir. Bu mimari, Olay Güdümlü (Event Driven) Mimariye oldukça benzemektedir. Platform bir Pub/Sub yapısı üzerine inşaa edilir ve servisler birbirleri ile mesajlar ile haberleşir. Bu mimaride event’lerin yerine mesajlar ve notification’lar almıştır.

Bizim tasarladığımız servis üzerinden örneklediğimizde; kullanıcı talebi ile (1 numaralı bağlantı) check-in servisi süreci başlatır, buna paralel (asenkron) olarak ödeme işleminin başlatılması için Message Broker aracılığıyla payment servisine bir notification gönderir (3 numaralı bağlantı). Servisler iş parçacıklarını yerine getirdiğinde ise bir done mesajı fırlatır, eğer ki bir işin bitmesini bekleyen servisler varsa bu done mesajı ile tetiklenir ve süreç bittiğinde ilgi serviste bir done mesajı fırlatır. Süreci yöneten Check-in mikroservisi son done mesajı ile tetiklenir ve kullanıcıya bir mesaj dönerek süreci tamamlayabilir. Kullanıcı bildirimleri asenkron olarak da kurgulanabilir bu durumda ilk request (1 numaralı bağlantı) sonrası servis bir dumy response (2 numaralı bağlantı) dönerek sürecin başladığını bildirir.

Mesaj Tabanlı Mimari (Message Driven Architecture)

Bu mimari yaklaşımda Message Broker olarak kullanılabilecek bir çok araç mevcuttur; Amazon Simple Notification Service (SNS), Azure, Firebase, vb. gibi cloud teknolojilerinin yanı sıra, kendinizin yönetebileceği veya hizmet olarak satın alabileceği; Kafka, RabbitMQ, vb. araçları tercih edilebilir.

Kaynaklar