RabbitMQ Exchange Types — .Net Core ile Giriş
Merhaba arkadaşlar bugünkü yazımda “.Net Core ile RabbitMQ’ ya Giriş” ile ilgili yazımın devamı olan “RabbitMQ Exchance Types” hakkında konuşacağız.
Her ne kadar RabbitMQ Exchance Types (aramalarda erişilebilmek adına) desemde, aslında Exchance Type’lar AMQP’un(Advaced Message Queue Protokol) parçalarıdır. Peki o zaman baştan başlayalım.
AMQP Nedir?
AMQP bir mesajı (bu herhangi bir şey olabilir) uygulamalar veya kuruluşlar arasında iletişim sağlanması için oluşturulmuş açık bir standartdır. Bu sayade farklı platformlardaki uygulamalar arasında güvenilir bir mesajlaşma sağlanabilir.
Neden AMQP’ye ihtiyaç duyuldu (Business Case)?
Kısaca aşağıdaki şekilde sıralayabiliriz.
- Farklı Platformlardaki uygulamaları birbirine bağlamak, (Bu sayade ilgili iş için en uygun platform veya dilde uygulama geliştirilebilir.)
- Asenkron çalışabilmek,
- Yeni ve değişen ihtiyaçlara kolayca cevap verebilmek.
AMQP Exchange ve Exchange Types
Exchange Nedir?
Exchange, Producer’dan gelen mesajı alıp isteğe bağlı olarak Queue’ye yönlendiren varlıktır diyebiliriz. Başka bir deyiş ile message routing agent diyebiliriz. Peki bunu neye göre yapıyor? İşte burada Exhange Type’lar devreye giriyor.
Not: Exchange Type sadece producer tarafını ilgilendirir. Consumer, Queue ile ilgilenir.
Exchange Types
- Direct Exchange
- Header Exchange
- Fanout Exchange
- Topic Exchange
Direct Exchange
Default olan Exchange tipidir. Mesaj Routing-Key bazlı olarak Queue’ya gönderir. Mesaj gönderildiği anda mesajın header’ı ile gönderilen Routing -Key ile tüm Queue’lar taranır ve mesaj, ilgili Routing-Key’e bind edilmiş tüm Queue’lara iletilir. Bulmaz ise mesaj ignore edilir.
Header Exchange
Routing-Key’e göre değilde mesaj ile birlikte gönderilen header değeri ile Queue’ya bind edilmiş değeri “x-match” key’ine verilen all veya any değerine göre match eder ve mesaj uygun queue’lara iletilir.
Fanout Exchange
Mesajı bir exchange bağlı tüm queue’lara iletilen exchange tipidir. Bu exchange tipi aynı mesajın birden fazla queue’ya iletilmesi ihtiyacı için uygundur. Örnek olarak oluşturulan siparişin hazırlanması için depo kuyruğuna iletilmesi ile birlikte kargo için bir kayıt açılması için kargo kuyruğuna da eklenmesinin istenmesi gibi durumlarda kullanılır.
Topic Exchange
Gönderilen mesaj, header ile gönderilen Routing-Key’in Queue’nun bind edildiği Routing Pattern’e göre eşleştirmesi ile Queue’ya iletilmesi sağlanır. Belli patternelere göre mesajın iletilmesi istenildiğinde kullanılabilir.
Bu kadar konuşma yeter sanırım. Gelelim bunları proje içerisinde nasıl kullanacağımıza;
Öncelikle Docker ile RabbitMQ’yu ayağa kaldıralım.(Bunun için pc nizde Docker kurulu olması gerekiyor. Kurulu değil ise aşağıda size uygun linklerden adımları takip edebilirsiniz.)
Kurulum
docker run -d — hostname my-rabbit — name myrabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management
ilgili komutu çalıştırdığınız browserdan localhost:5672 adresine girdiğimizde aşağıdaki gibi bir ekran ile karşılaşmanız gerekiyor.
Örneğimi oluşturmadan önce yapacağımız işlemi kısaca anlatayım. Öncelikle her exchange tipi için 3 adet queue oluşturacağız ve bu 3 Queue’ya exchange üzerinden mesajı nasıl ileteceğimize bakacağız ve yine exchange tiplerine göre yönlendirmelerin nasıl olduğunu açıkça görüyor olacağız.
Öncelikle dotnet cli ile bir adet Producer (üretici) projesi oluşturalım.
Yine aynı şekilde bir adet Consumer (mesajı tüketen taraf) projesi oluşturalım.
Daha sonra proje visual studio code ile açmak için aşağıdaki komutu çalıştırıyoruz.
Şimdi makalemiz konusu olan işlemlerimizi yapacağımız Producer projesine gelelim.
Projesinin dosyaları aşağıdaki gibidir.
Producer içerisindeki program.cs aşağıdaki gibidir. Test etmek istediğiniz Exchange tipini değiştirerek tüm tipler için çalıştırabilirsiniz.
Tüm exchange tipleri için örnek aşamasında burayı değiştiriyor olacağız.
Öncelikle Helper’larımızı aradan çıkaralım.
RabbitMqHelper classımızdan connection oluştururken destek alacağız. Lazy sınıfı ile ihtiyacımız olduğu andan itibaren singleton olarak Instance’sini kullanıyor olacağız.
StringExtensions ile string işlemlerimiz için destek alıyor olacağız. 2 adet extension method içermektedir. String to byte[] ve byte[] to string convert işlemlerini yapmaktadır.
Sıra geldi interface’lerimize;
IExchangeFactory interface’ni “Exchance ve Queue’ların oluştulduğu concrate claslarımıza implement edeceğiz. İçeriği aşağıdaki gibidir.
ISendMessage interface’ni Exchange tipine göre mesajı göndereceğimiz concrate claslarımıza implement edeceğiz. İçeriği aşağıdaki gibidir.
Artık yardımcı olacak işlerimizi tamamladığımıza göre asıl işlemlerimize geçebiliriz.
Direct Exchange Sample
Direct exchange, yukarıda belirttiğimiz gibi default olan excahange tipidir. Exchange ve Routing-Key’e göre eşleşen Queue’yu bulur ve mesajı iletir.
DirectExchange.cs içeriği gibidir.
Neler yaptığımıza göz atacak olur isek. DirectExchange, IExchangeFactory Interface’ini implement eder. Buna bağlı olarak bir adet method içerir. Bununla birlikte yukarıda belirttiğimiz gibi 3 adet Queue için const içerir ve yine buna bağlı olarak adından da anlaşılacağı üzere her bir Queue ile eşleşmesi için 3 Routing-Key const olarak tutulmaktadır.
CreateExChangeAndQueue methoduna göz atacak olur isek;
Öncelikle bir connection örneği almakla beraber buna bağlı olarak bir channel oluşturulmakta ve sonrasında Direkt Exchange tipinde bir exchange tanımlanmaktadır.
Daha sonra Queue oluşturuyor ve Exchange’e bağlı olarak Queue, Routing-Key ile bind edilmektedir. Eşleşmeler şu şekilde olmuştur.
Direct-queue-1 =>direct-key-1"
Direct-queue-2 =>direct-key-2"
Direct-queue-3 =>direct-key-3"
DirectMessage.cs içeriği aşağıdaki gibidir.
Burada Exchange Name ve Routing-Key’e göre mesajımızı Queue’ya ilettiğimiz kısımdır. ISendMessage Interface’ini imlement etmektedir.
3 mesaj için tanımlı readonly property mevcut. SendMessage methoduna göz atacak olursak;
Yine işlemlere başlamadan önce connection ile birlikte mesajı ileteceğimiz bir channel oluşturulmaktadır.
Channel’in BasicPublish methodundan yararlanarak mesajı iletiyoruz. Peki mesaj Queue’ya nasıl iletildi. Gördüğünüz gibi aslında methoda verdiğimiz parametrelerin hiç birinde Queue ismini vermiyoruz. İşte bu aslında konumuzun en açık resmi. Producer Queue’yu bilmiyor. Exchange Name ve Routing-Key’e göre Queue’yu bulur ve mesajı iletir.
Program.cs main methodun içeriğini aşağıdaki şekilde değiştirelim.
Projeyi çalıştırıp RabbitMQ ->Queues sekmesine girdiğimizde sonuç aşağıdaki gibi olacaktır. Mesajlar birer birer iletilmiştir.
Header Exchange Sample
HeaderExchange.cs içeriğine göz atacak olursak aşağıdaki gibidir.
Queue ve Exhange Name ile ilgili adımları geçiyorum. DirectExchange.cs’de olduğu gibi CreateExChangeAndQueue methodu yer almaktadır.
Aynı şekilde connection ve channel oluşturulduktan sonra öncelikle Exchange Name ve tipine göre Exchange oluşturulur. Heman ardından Queue tanımlanır ve ilgili exchange name ve header keylerine göre bind edilir. Header key yukarıda belirttiğimiz gibi x-match key’ine göre tüm keylerin veya sadece bir tanesinin iletilen mesaj headerında olmasını bekler.
Örneğimiz üzerinden konuşacak olursak bir kişi eğer “header-queue-2” ye mesaj iletmek ister ise header içerisinde (“Fourth”, “D”) veya (“Third”, “C”) olması yeterli. Ancak “header-queue-3”e göndermek isterse (“First”, “A”) ve (“Third”, “C”) yer alması gerekmektedir.
HeaderMessage.cs içeriğine göz atacak olursak aşağıdaki gibidir.
Farkettiğiniz gibi burada Routing-Key devreden çıktı. (“boş string” olarak tanımlandı”). Mesaj, Exhange Name ve BasicProperties parametresinin Header “property”si üzerinden verilen keyler üzerinden queue ile eşleştiriliyor.
Gönderdiğimiz mesaj ile birlikte ilettiğimiz keylere bakacak olursak “Message2” sadece “header-queue-2” ya iletilirken “Message3” tüm header “queue” lara (“header-queue-1”,“header-queue-2”,“header-queue-3”) iletilecek.
Program.cs main methodun içeriğini aşağıdaki şekilde değiştirelim.
Projeyi tekrardan çalıştıralım. RabbitMQ ->Queues sekmesine girdiğimizde sonuç aşağıdaki gibi olacaktır.
“Message3” tüm Queue’lara. “Message2” “header-queue-2”ye, “Message1” ise “header-queue-1” ve “header-queue-2”ye iletilmiştir.
Fanout Exchange Sample
FanoutExchange.cs içeriğine göz atacak olursak aşağıdaki gibidir.
Tekrar işlemleri es geçip farklı olarak yapılan işlemlere göz atacak olursak; Routing-Key Header Exchange de olduğu gibi “boş string” olarak tanımlanmıştır ve Queue’lar arada hiçbir şey olmaksızın direkt ExchangeName’e bind edilmektedir.
FanoutMessage.cs içeriğine göz atacak olursak;
Mesaj Exchange Name üzerinden iletilmektedir. Bu mesaj iletilen Exchange Name’e bind edilmiş tüm Queue’lara iletilmektedir. Subscribe olarak da düşünebilirsiniz. FanoutExchange için oluşturduğumuz örneğe bakacak olursak her mesaj üç Queue’ya da iletilecektir.
Program.cs main methodun içeriğini aşağıdaki şekilde değiştirelim.
Projeyi tekrardan çalıştıralım. RabbitMQ ->Queues sekmesine girdiğimizde sonuç aşağıdaki gibi olacaktır.
Yukarıda da belirttiğimiz gibi fanout tarafında gönderdiğimiz tüm mesajlar fanout tipinde oluşturulmuş tüm Queue’lara iletilmiştir.
Topic Exchange Sample
TopicExchange.cs içeriğine göz atacak olursak aşağıdaki gibidir.
Diğerlerinden faklı olarak Queue bind edilirken pattern belirtilmekte. Mesaj, Routing-Key ile ilgili patterne uyan tüm Queue’lara iletilmekte.
TopicMessage.cs içeriğine göz atacak olursak aşağıdaki gibidir.
Burada pattern olarak * ve # kullanılmaktadır.
* Bir veya daha fazla match sağlaması durumunda kabul edilir.
# Sıfır veya daha fazla match sağlaması durumunda kabul edilir.
Program.cs main methodun içeriğini aşağıdaki şekilde değiştirelim.
Projeyi tekrardan çalıştıralım. RabbitMQ ->Queues sekmesine girdiğimizde sonuç aşağıdaki gibi olacaktır.
Message2 “topic-queue-2”ye, Message1 ve Message3 tüm Queue’lara iletildi.
Consumer
Şimdi sıra geldi resultları görebileceğimiz Consumer projesini oluşturmaya. Projenin dizinine girmek için;
RabbitMQ Client dosyalarını projeye dahil etmek için ise;
komutlarını çalıştıralım.
Program.cs kontrol ettiğimizde içeriği aşağıdaki gibidir. Tüm Exchange Type’ları için oluşturulan Queue mesajlarını almak için Consumer oluşturulmaktadır. Program.cs içeriği aşağıdaki gibidir.
“dotnet run” ile Consumer projesini çalıştırdığımızda hangi mesaj hangi Queue’ya iletilmiş görebilirsiniz.
Sonuç
Mesajı iletirken Queue’ya iletmek yerine Routing-Key ile birlikte exchange name ve tipine göre iletmemiz bizlere esneklikler sağlamaktadır. Bu sayede Queue’yu bilmemize bile gerek olmuyor. İhtiyacımıza göre bu tiplerden herhangi birini veya birkaçını kullanabiliriz. Örneklerimizde basit olarak Exchange Type’ları tanımaya çalışmak ile birlikte projemizde nasıl kullanacağımızı öğrendik. Umarım faydalı olmuştur.
Proje kodlarına buradan ulaşabilirsiniz.
Bir sonraki makalede görüşmek üzere, sağlıcakla kalın.
Yararlanılan kaynaklar
https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf
Feyyaz Acet