Microservice Mimarisinde Haberleşme ve CAP Kullanımı

Vedat ERMIS
Kariyer.net Tech
4 min readAug 14, 2022

--

Bu yazımda, Microservice mimarisinde kullanılan birkaç mesajlaşma türünden biri olan EventBus mesajlaşma türünü ele alacağım. EventBus altyapısını ise opensource bir kütüphane olan CAP ile yapacağız.

Peki bu EventBus Nedir ?
Bir servisin yaptığı işlemi ve sonucunu bir event fırlatarak diğer servislere de haber vermek için bir mesaj kuyruğuna (RabbitMq, Kafka…) bir mesaj bırakması ve bu mesaj kuyruklarını dinleyen diğer servislerin bu mesajı alarak gerekli işlemleri yapmasıdır.

CAP Nedir ?
CAP .Net standart tabanlı distributed transaction yapısıyla başa çıkmak için geliştirilen EventBus işlevine sahip, hafif ve kullanımı kolay olan mesajlaşma kütüphanesidir.

CAP mesajlaşma kütüphanesi olası veri kayıplarını önlemek için Local Message Table yaklaşımını benimsemiştir. Publish ve Receive edilen her mesaj local veritabanında saklanır.

CAP’ in desteklediği araçlar ise;

Mesajlaşma tarafında

  • Kafka
  • RabbitMq
  • AzureServiceBus
  • AmazonSQS
  • NATS
  • RedisStreams
  • Pulsar

Veritabanı Tarafında

  • SqlServer
  • MySQL
  • PostgresSQL
  • MongoDB

Bu kadar teorik bilgiden sonra şimdi de pratik kısmına girelim.

Projemize CAP’ in kurulumunu yapmak için birkaç nuget paketini projemize eklememiz gerekmekte. Ben bu örnekte RabbitMq ve PostgresSQL ile çalışacağım için aşağıdaki paketleri yüklüyor olacağım.

Install-Package DotNetCore.CAP
Install-Package DotNetCore.CAP.RabbitMQ
Install-Package DotNetCore.CAP.PostgreSql

CAP’ in bir diğer özelliği ise kendisine ait çok kolay bir şekilde implemente edebileceğiniz bir Dashboard’ ının olmasıdır. Eğer kullanmak isterseniz aşağıdaki nuget paketini de kurmamız gerekiyor.

Install-Package DotNetCore.CAP.Dashboard

Nuget paketlerini ekledikten sonra CAP’ in Local Message Table olarak kullanacağı database’ in yapılandırma kısmını yapmakla devam ediyoruz.

Bu aşamada EntityFramework kullanıyor olacağız;

Ardından CAP’ in yapılandırmasını yapıyoruz.

Burada belirttiğimiz DefaultGroupName aslında bir abonelik grubunu ayarlamak için kullanılır. Aynı mesajı birden fazla microservice üzerinde işletmek için bunu tanımlıyoruz. Eğer bir grup adı belirtilmez ise default olarak assembly adını alır.

Bir de veritabanını otomatik olarak oluşturmuyor. Bu işlemi manuel olarak yapıyoruz.

Yapılandırma kısmı bu kadar artık mesaj yollamaya ve bu mesajı dinleyen consumer yapısını kurmaya hazırız.

Benim senaryomda 2 tane microservice var. Bu servislerden birisi Product diğeri ise Category. Category servisinde CategoryName alanı değişen bir kaydın, Product servisinde de çalışması için bir Event fırlatıyoruz ve değişen CategoryName, Product servisindeki kayıtlarıda etkiliyor.

İlk önce ICapPublisher interface’ ini ve ApiContext’i inject ediyoruz.

Ardında Event’imizi fırlatmak için servis metodumuzu yazıyoruz.

Publish işlemi bu kadardı şimdi ise yolladığımız mesajı karşılayan Consumer sınıfımızı yazalım.

Consumer oluştururken iki şekilde oluşturabilirsiniz.

Birincisi Controller katmanında diğeri ise Service katmanında. Ben bu örnekte servis katmanını tercih ettim.

Burda dikkat edilmesi gereken notka; Service katmanında Consume işlemi yapmak istiyorsak, servisimizi ICapSubscribe interface’ inden türetmeliyiz. Controller tarafında böyle bir şeye gerek yok.

Şimdi de oluşan local dataya bir göz atalım.

Yukarıdaki tablolar CAP tarafından otomatik olarak yönetilmektedir. Şimdi de bir Dashboard’a göz atalım. Dashboard’a ulaşmak için http://localhost:xxxx/cap adresine gidiyoruz.

Bu adresi değiştirmek için yapılandırmayı şöyle değiştirmeliyiz;
options.UseDashboard(x => x.PathMatch = “/adres”);

CAP’ in beğendiğim bir diğer özelliği de CallBack yapısı. Producer ile bir mesaj yolladıktan sonra Consumer’ dan gelen mesajı dinler. Bu sayede consumer’ dan gelen sonuçlara göre algoritmamızı geliştirebiliriz.

Üstteki örneğe göre kullanımı şu şekilde;

Publish ettiğimiz sınıfı ICapSubscribe interface’ inden türetmemiz gerekiyor ayrıca Publish metodunu da callback için bir isim belirliyoruz adı veriyoruz.

Consumer tarafında ise dönüş tipini string olarak değiştirip istediğimiz değeri geri dönüyoruz ve işlem tamamlanıyor.

Buraya kadar yaptığımız işlemler bir hata yönetimi bulunmuyor. Yani bir servis aldığım mesajı işlerken bir hata ile karşılaştığında, kendisine mesajı yollayan servisin bu hatadan haberi olmuyor.

Bu konuyu Distributed Transaction başlığı altında başka bir yazımda işliyor olacağım.

Kaynaklar:

--

--