Mikroservis + RabbitMQ uygulaması - 2

Bir önceki yazımda mikrsoervis mimarisinin üzerine RabbitMQ entegre edileceğini anlatmıştım. Bu yazıda RabbitMQ ile ilgileneceğiz ve bazı detaylarını göreceğiz. Rabbitmq nedir, hangi işlevleri yerine getirebilir, nasıl kurulup çalıştırılabilir gibi sorulara bakacağız. Sonrasında message broker yapısının temelindeki exchange türlerine bakıp diğer broker 'lardan kısaca bahsedip bitireceğim. Kod yazılmayan sıkıcı bir yazı olacak :) Sistemin mimarisi referans olarak burada dursun.

RabbitMQ nedir, önemli özellikleri nedir

JavaEE ekosisteminde JMS (java message service) şeklinde bir protokol bulunuyor. Zamanında enterprise uygulamalar birbirleri ile haberleşmek için bu protokolün implementasyonlarını kullanıyorlardı. Tıpkı restful web servislerinde http protokolünü jersey ile kullanmamız gibi. Bu implementasyonlar sınırlı idi ve zaten o günlerde monolitik uygulamalar çok da fazla mesajlaşma altyapısı gerektiren uygulamalar olmuyordu. Gün geçtikçe restful servisler, web 2.0 ve sonrasında mikroservisler gelişti ve monolitik olmayan modüler küçük uygulamalar arasındaki haberleşme ihtiyaçları da arttı. Sistemler büyüdükçe uzun süren asenkron işlemler de ortaya çıkmaya başladı. Bu trend sonucunda mesajlaşma işlemi JMS 'yi AMQP 'ye (Advanced Message Queuing Protocol) dönüştürdü ve bu protokolün ürünleri çıkmaya başladı.

Bu yüzden çeşitli message broker 'lar yani aracılar türemeye başladı. Bu aracılardan birisi olan RabbitMQ 2010 yılında 2.0.0 sürümünde amqp 0.9.1 'i destekleyerek olgun bir message broker ünvanına sahip oldu. Bu protokolü desteklemesi aslında bir message broker 'ın yapması gereken mesaj iletim mekanizmasını sağladığını gösteriyor. Fakat ilk yazıda da belirttiğim gibi sadece mesaj kuyrukları ve iletimi ile yetinmiyor ve üzerine ekstra özellikler ekleniyor. Dilerseniz bütün sürüm haberleri burada.

Özetle rabbitmq ne yapar? AMQP protokolünü implement ederek çeşitli kaynaklardan mesajlar alır ve bunları çeşitli kaynaklardaki api 'leri sayesinde dinleyerek iletir. Yani burada rabbitmq 'nun kendisinin dışında bir de api 'leri mevcut. Rabbitmq da bir uygulama aslında ve sunucuda servis olarak çalışıyor. Bu servis belli bir portu dinliyor ve gelen mesajı (payload) kendi içerisinde işlemlere tabi tutuyor. İşte bu uygulama Erlang ile yazılmış. Bu yüzden rabbitmq kurmak için önce erlang kütüphanesini bilgisayarınıza kurmanız gerekiyor.

RabbitMQ buradan indirilebilir. Ben kendi bilgisayarımda windows kullandığım için hazır installer kullanarak yapabilmiştim. Bazı durumlarda önce erlang kurup sonra rabbitmq kurmanız gerekebiliyor. Linux için de kurulumun nasıl yapılacağını gösteren komutlar download sayfasında mecvut. Fakat eğer erlang 'ı ayrıca kuracaksanız bir uyumluluk sorunu yaşayabiliyorsunuz. Erlang ile rabbitmq versiyonlarının uyumluluğunu bir matris ile burada gösteriyorlar. Kurulumu tamamladığınızda bilgisayarınızda çalışan RabbitMQ isimli bir servis göreceksiniz.

Artıları ve eksileri nelerdir

Henüz rabbitmq ile bir etkleşimde bulunmayacağımız için servisin çalıştığını gördüyseniz şimdilik dursun. Çünkü biraz da bu aracı incelememiz gerekiyor. RabbitMQ 'nun çok sayıda işlevi yerine getirebildiğini söylemiştim. Bunlar arasında yük dengeleme var, resiliency var, çeşitli kuyruk yapıları var kendi spesifik özellikleri ile, monitoring var, backup ve restore işlemleri var, high availability özellikleri var, authorization ve authentication var, loglama var... Güzel bir liste değil mi :) Daha bitmedi. Mesaj gönderen ve alan (publisher ve consumer) api 'leri tam 11 dilde mevcut. Python, Java, Ruby, PHP, C#, JavaScript, Go, Elixir, Objective-C, Swift, Spring AMQP. Bunlar artıları olarak sıralanabilir. Sonuçta bu kadar özelliği barındırması ve stabil çalışabilmesi (production ready) yeterince güven veriyor. Çok açıklayıcı dökümantasyonu ve örnekleri de var. Daha ne olsun.

Bu kadar özelliğinin olması kulağa hoş geliyor tabi ama bazı eksileri de bundan kaynaklanıyor. Rabbitmq 'yu ciddi manada kullanmak istiyorsanız size resmen bir uzmanlık alanı gerekiyor. Başlı başına bir ürün çünkü. Ayrıca başınıza bir iş açtığınızda veya bir hata yaptığınızda bunun çözümünü aradığınızda 4-5 farklı kimlikle karşınıza çıkabiliyor. Mesela programcıları tembel olan bir yazılım firmasında yazılan kodları kısaltıp hatta belki mikroservisleri bile yanlış kullanıp sistemin merkezinde otorite olarak rabbitmq koyanları görebiliyorsunuz. Veya aynı sorunları çok farklı sebeplerle yaşayan insanlar görebiliyorsunuz. Veya sizin spesifik case 'inize veya bilgisizliğinize uyan bir açıklama bulamayabiliyorsunuz. Bütün bunlar biraz da öğrenme eğirisini dikleştiriyor ve hata gidermeyi zorlaştırabiliyor. Dahası kendi kendinizce koskoca bir rabbitmq 'yu alıp şu işler için kullanacağım demekle doğru kullanmış olmuyorsunuz. Donanımlı bir araba gibi düşünün, kullanmanın bir raconu var.

Yük dengeleme ve hata yakalama nasıl yönetilebilir

Mikroservisler ile çalışırken sistemin bir şekilde load balance, error handling (fault tolerance) ve resiliency kavramlarını işletmesi gerektiğini söylemiştim. Bu 3 kavramdan 2 tanesi (load balancing ve resiliency) eureka (ribbon) + gateway (resilience4J) ikilisi ile sağlanıyordu. Hata yakalama ve transaction yönetimini kendimiz bir şekilde mvc uygulamasına oturtabilmiştik. İşte bütün bunları yapabilmemizin sebebi kodları bizim yazıyor olmamız. Bu araçlar için hazır tool 'lar kullansaydık onların merhametine kalacaktık :)

Fakat en baştaki mimariye bakarsanız MVC uygulaması ile mail servisi arasındaki bütün iletişim RabbitMQ 'nun sorumluluğunda. Bu yüzden bu 3 önemli kavramı da bir şekilde handle etmek zorunda. Benim rabbitmq konusunda derin bilgim yok ama kısaca bildiğim kadarı ile bahsedeyim ki sizler ne bununla ben ne yapıcam sorularının cevabını az da olsa bulmuş olasınız.

RabbitMQ ile load balancing yani yük dengelemek için elinizde bazı seçenekler var. Mail servisini çoklayarak dinleyicileri çoğaltabilirsiniz. İlgili kuyruğa gelen mesajları alıp değerlendirebilirler. Fakat bu rabbitmq üzerindeki yükü azaltmaz ve sonuçta yine bir kuyrukta binlerce bekleyen işleme yol açabilir. Her ne kadar çoğunlukla asenkron işlemler için message broker kullansak da bu kuyrukların büyümesi ideal bir çözüm olmayacaktır. Bu dinleyici servisler her zaman 1 tane olmak zorunda demek değil tabi ki, o kısmı size kalmış.

Load balancing için birden fazla rabbitmq ayağa kaldırmak gibi bir çözüm olabiliyor, bunların önüne bir load balancer koyarak rabbitmq 'lar üzerindeki yük azaltılabiliyor. Bu çözümlerin hangisi iyi hangisi kötü şeklinde bir soruya cevap vermek zor. Bunun için tasarladığınız sistemi ve rabbitmq 'nun özelliklerini daha detaylı bilmek gerekir. Yine de bu durumda load balancer özellikleri olan bir tool 'un önüne tekrar load balance koymak pek mantıklı olmuyor gibi.

RabbitMQ kendi içerisinde node 'lar bulunduruyor. Sırf ekstra bir yük dengeleyiciye gerek kalmasın diye kuyrukları ve exchange türlerini barındıran bu node yapılarını ekleyip çıkarabiliyorsunuz. Bu sayede aslında birden fazla rabbitmq kullanılıyor gibi olabiliyor. Dilerseniz üzerine kendiniz de bir şekilde dinleyici metodları çoğaltmayı deneyebilirsiniz. RabbitMQ ile clustering işlemlerini detaylı bir şekilde anlatan dökümantasyon da burada.

RabbitMQ ile resiliency ve fault tolerance sağlamak için sistemin çökmesi veya mesajların iletilememesi durumunda önlemler alabiliyor olması gerekiyor. Bunları da düşünmüşler tabi ki. RabbitMQ iletemediği mesajları boşuna kuyrukta tutmamak için iletilemeyenlerin ayrıldığı kuyruğa yönlendirme yapabiliyor. Burada belli timeoutlar ve retry mekanizmaları gibi koşullar da işin içine girebiliyor. Ayrıca yedekli çalışarak kuyruğun biri patlarsa veya kaybolursa diğerinden devam edebiliyor. Kuyruktaki veriler dosya sistemine yazılıyor ve rabbitmq veya sunucu bir şekilde restart olursa kaldığı yerden devam edebiliyor. Mesaj iletimi ise tek yönlü olabildiği gibi cevap döndürecek şekilde de kurgulanabiliyor. Her mesaj iletildi bilgisini acknowledgement ile döndürebiliyor. Bu geri bildirime göre alınan hatalarda da deadletter kuyruklarına iletim yapılabiliyor.

Gördüğünüz üzere bir tool ile mikroservis mimarimizdeki eureka ve gateway 'in özelliklerini sağlayabilmiş olduk. Tabi bu kadar sorumluluğu olan bir sistemin bakımı da zor olacaktır ama bunun felsefesini son yazıda yapacağım. Bütün bu sistemin çekirdeğinde mesaj iletimi için exchange yani takas mantıkları yatıyor. Bu mantıkları belirlediğinizde gönderici (publisher) ve alıcı (consumer) metodlarınızı da ona göre yazmanız gerekiyor. Bu kadar kritik bir nokta aslında.

Exchange türleri nelerdir

AMQP 0.9.1 demiştim ya, bu protokol ile bu takas yöntemleri belirleniyor. Detayları burada bulabilirsiniz. Kısaca 4 temel exchange türü bulunuyor. Direct, topic, fanout ve headers exhange. Bunlar için tek tek resimler koyarak kalabalıklaştırmayı istemedim. Bu yüzden bu yazıya bakarak anlamaya çalışın lütfen :)

RabbitMQ çalışma mantığında takas türü, kuyruk ve routing key önem arz ediyor. Bir mesajı rabbitmq 'ya göndermek için hangi exhange 'e (aynı türde birden fazlası olabileceği için) göndereceğinizi belirtiyorsunuz. Bu exchange türüne göre gelen routing key 'e bakıyor ve spesifik işlemini gerçekleştirerek ilgili kuyruğa yönlendiriyor. Exhange olmadan kuyruk olmuyor diye biliyorum. Bu yüzden exchange türleri gelişiyor.

Fanout exchange yapısında bu exhange 'e bağlı olan bütün kuyruklara routing key 'lerden bağımsız otomatik olarak mesaj iletiliyor. Direct exchange yapısında gönderilen routing key ne ise bu route ile tam eşleşme sağlanan kuyruğa gönderiliyor. Mesela "email.receipt" gibi bir ifade ile yönlendirme yaptığınızda ancak ve ancak "email.receipt" routing bilgisi ile çalışan kuyruğa veri gidiyor. Headers exchange ise gönderdiğiniz mesajla beraber gelen header bilgilerine bakarak ilgili kuyruğa yönlendirebiliyor. HTTP header 'ları gibi mesajların da header 'ları oluyor, temelde http metodları kullanıldığı için.

Son olarak topic exchange ise muhtemelen bunların en popüleri. Bir routing key 'i içeren veya bir routing key ile başlayan mesajları belli kuyruklara gönderebiliyor. Örneğin "email.*" yazdığımda kuyruklarda "email.special" veya "email.normal" gibi iki kuyruk bulunursa ikisi de "email." topic 'ine yani konusuna abone olmuş oluyor. Buradaki en büyük özellik reqular expression gibi bir ifade ile kuyruklara yönlendirme yapabilmek. Bütün bu exchange türlerinin simülasyonunu yapabileceğiniz şirin bi uygulama yazmışlar. Buradan ulaşabilirsiniz ve deneme yanılma yöntemi ile gözlemleyebilirsiniz.

Tabi ki hangi exhange yapısını kullanacağınızı iyi belirlemeniz gerekiyor. İlerde routing key 'ler bir şekilde değişirse ve hangi mesajın kime gittiği dökümante edilmemişse ara ki bulasın. Hangi tür exchange yönteminin size uygun olup olmadığını ancak siz kendiniz söyleyebilirsiniz. Bu yapıların birbirine göre üstünlüğü bulunmamakla beraber kendi getirileri ve götürüleri olacaktır. Bu kadar övdük rabbitmq 'yu madem biraz da alternatiflerine bakalım.

Alternatifleri nelerdir

Detaylı bilgim olmasa da stackshare.io sağolsun message broker araçları için epeyce veri sağlıyor. Görünüşe göre Kafka rabbitmq 'dan daha profesyonel özelliklere sahip, sadece mesaj değil stream mantığı ile çalışabilmesi ve çok büyük verileri handle edebilmesi gibi. Cloud native olan Azure service bus ve Amazon SQS serverless olarak çalışabiliyor ve doğal olarak coğrafi anlamda çeşitli noktalarda konumlandırılabiliyor. Tabi Azure service bus .net ile tam uyumlu olduğu için .net projelerde kullanmanız epeyce kolaylaşacaktır diye düşünüyorum. Bu arada rabbitmq diğer tool 'lara göre yavaş kalabiliyormuş fakat çok yoğun data ile uğraşmadığınız sürece bunu fark edeceğinizi sanmıyorum. IBM MQ ise cloud tabanlı olmayan sanırım en büyük mq ürünü ve biraz da tuzlu muhtemelen. VM olarak veya container şeklinde paketlenmiş ve isteğe göre kurulabiliyormuş. Rabbitmq gibi önce erlang sonra rabbitmq şeklinde değilmiş. Message broker tool olarak rabbitmq 'ya alternatif oluşturabilecek bütün ürünler de sanırım bu sayfada mevcut.

RabbitMQ üzerine neden bu kadar araştırma?

Günümüzde message broker 'lar ve kuyruklar ile iletişim yöntemi özellikle mikroservisler ile çok popüler olmuş durumda. Fakat bu demek değil ki her türlü mikroservis uygulamasında bir message broker kullanılmak zorunda. Mikroservisler konu olduğunda sistemin her parçası bir parça da olsa diğerlerini etkleyebiliyor. Çünkü sonuçta birbirleri ile haberleşen minik parçalar bunlar. Bu yüzden üzerine yıllardır çalışılmış ve uzmanlık alanlarına dönüşmüş olan message broker 'ları kullanmadan ve bunlara bağımlı kalmadan önce iyi analiz etmek gerekiyor. Bu yazıda RabbitMQ 'yu neden ve nasıl kullanabiliriz gibi soruları incelemiş olduk. Kararımızdan pişman olmamak için alternatiflerine de baktık. Artık RabbitMQ 'ya mesaj göndereceğiz ve yönetim konsoluna bakacağız. Bir sonraki yazıda görüşmek üzere :)


Bir yorum yazabilirsiniz