RabbitMQ ile Mesaj Yönetimi
Message queue yapıları, bir kaynaktan(servis, uygulama vb) alınan mesajı başka bir kaynağa iletmek için kullanılır. Özellikle yoğun veri akışının olduğu sistemlerde, çok sayıda verinin işlenmesi esnasında yaşanabilecek tıkanmaların önüne geçmek adına, verileri kuyrukta tutma ve sonrasında istenen kaynağa yazma prensibiyle çalışır.
RabbitMQ, açık kaynak kodlu en çok kullanılan ‘message broker’ yapılarından birisidir. Bu yazıda RabbitMQ ile ilgili bazı temel noktalara değineceğim.
RabbitMQ’nun Reddit, Trivago, Runtastic, BlaBlaCar gibi şirketler tarafından kullanıldığı StackShare‘da belirtilmiş. RabbitMQ dışında Apache Kafka, MSMQ, ActiveMQ gibi farklı message queue araçları da günümüzde sıkça kullanılmaktadır.
RabbitMQ’nun çalışma prensibine bir örnek üzerinden bakalım. Herhangi bir kişi mektubunu postaneye teslim eder ve mektubun alıcıya ulaşacağını bilir. Burada RabbitMQ yapısı postane gibi düşünülebilir.
Yapıya özel bazı terimler vardır.
- Producer: Mektubu gönderecek olan kişi
- Queue: Mektupların konulduğu posta kutusu
- Consumer: Mektubu alıp okuyacak olan kişi
Queue denen kısım mesajların tutulduğu bölgedir ve boyutu disk kapasitesine bağlıdır. Mesajların depolandığı kalıcı bir yedek bölümü gibi düşünülebilir. Adı üstünde bir kuyruktur bilet kuyruğu gibi.
Birden fazla gönderici(producer) birçok mesajı tek bir kuyruğa gönderebilir. Birden fazla tüketici(consumer) de mesajları tek bir kuyruktan alıp işleyebilir.
Gönderici(Producer) mesajı direkt olarak kuyruğa göndermez. Mesajı exchange diye tabir edilen terime gönderir. Exchange, binding key ve routing key diye tanımlanan terimlerle hangi kuyruğa gitmesi gerektiğini öğrenir ve mesaj o kuyruğa gider.
Örneğin resimdeki gibi kullanıcı bir pdf yaratma isteği yaptı. İstek kullanıcı maili ile paketlenip bir mesaj halinde gönderici(producer) tarafından exchange’e gönderildi. Exchange’de yer alan routing key değerine göre hangi rotaya yani hangi kuyruğa(queue) gitmesi gerektiğini öğrenip oraya gitti. Bu kuyruğun alıcısı olan tüketiciler(consumer listesi) de kuyruktan gelen mesajı alıp işlemeye başladılar.
C# projenizde RabbitMQ kullanabilmek için öncelikle aktif bir RabbitMQ sunucunuz olmalı. Bunun için ayrı bir RabbitMQ kurulumu yapabileceğiniz gibi Docker imajı ile de kullanabilirsiniz.
Docker ile ayağa kaldırmak için:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
Kodu çalıştırdığınızda http://localhost:15672 adresinden rabbitmq’ya erişebilirsiniz.
Varsayılan kullanıcı adı ve şifre: guest
RabbitMQ Exchange Tiplerinin C# ile Entegre Kullanımı
Direct
Bu tipte, mesaj bir veya birden fazla queue’ya gidebilir. Buradaki temel koşul şudur: gidecek olan mesajın routing key değeri ile mesajı alacak olan kuyruğun binding key değerleri birbiriyle aynı olmalıdır.
Fanout
Bu exchange tipinde mesaj, bağlı olduğu tüm kuyruklara gider.
Topic
Bu türde wildcard desteği kullanılabilmekte. Mesajlar içerisinde şu sırayla şu harflerin geçtiği rota(route) örüntüsü veya rota anahtarı ile eşleşen kuyruklara gider.
Headers
Bu yöntemde mesajın headers özelliğine bakılarak hangi kuyruğa yönlendirme yapılacağına karar verilir.
Round-Robin Yöntemi
RabbitMQ gelen mesajları işlemeye başlar. Eğer birden fazla aynı kuyruğu dinleyen tüketici(consumer) varsa her gelen mesaj boştaki tüketiciye gider ve bu tüketici sırasına göre mesajların işleme alınma adedi bitene kadar tekrar eder.
Örneğin bilet satın almak için 3 kuyruk var.
- 1. kuyruk elektronik müzik konseri için bilet bekleyenlerin bulunduğu kuyruk
- 2. kuyruk harbiye açık hava teoman konseri için bilet bekleyenlerin bulunduğu kuyruk
- 3. kuyruk senenin en iyi türk filmini izlemek isteyenlere özel olarak süslenmiş açık hava sineması için bilet bekleyenlerin bulunduğu kuyruk
Kamu Spotu: Formula 1 gibi yoğun talep edilen etkinlikler için bilet alamazsınız o yüzden hiç kuyruğa girmeyin.
Konumuza dönelim.
4 gişe var:
- Gişe1
- Gişe2
- Gişe3
- Gişe4
Bir kuyruk ve bu kuyrukta 10 kişi var: Kişi1, Kişi2…, Kişi10.
Burada kişileri mesaj(message), gişeleri tüketici (consumer) olarak düşünebiliriz.
- Kişi 1 => Gişe 1
- Kişi 2 => Gişe 2
- Kişi 3 => Gişe 3
- Kişi 4 => Gişe 4
- Kişi 5 => Gişe 1
- Kişi 6 => Gişe 2
- Kişi 7 => Gişe 3
- Kişi 8 => Gişe 4
- Kişi 9 => Gişe 1
- Kişi 10 => Gişe 2
Bu şekilde sıralı devam eden yapıya Round-Robin denmektedir. İşletim sistemi işlemcileri de her işlemi sıraya alırken buna benzer olarak sabit bir süreyle ilişkili olan Round-Robin algoritmasını kullanmaktadır. Hakkında detaylı bilgi Wikipedia sayfasından okunabilir.
Neticede bir işlem bitmedi diye diğer tüm işlemler arka planda bekleyecek değil. Birden fazla tüketicimiz(consumer) olduğunda rabbitmq ile paralelde işlem yapma yetisi kazandırabiliriz. Dolayısıyla 4t zamanda tamamlanacak işlemlerin tamamlanma zamanları ortalama t süreye kadar düşürülür. Performans olarak belki de 4 kat daha iyi bir yapı sağlanmış olur.
Acknowledgement
Mesela üstteki örnekten devam edelim. Teoman konserine bilet almak için bir kontrolden geçtiniz. Kontrol eden kişiyi kuyruğa mesajı gönderen gönderici kabul edelim. Sıra size geldi ve bilet alma işlemi başladı. Ne tesadüftür ki sıra sizdeyken sistem gitti, gider. Gişe görevlisi sistem gittiği için kuyruğun sonundaki kontrol eden görevliye kuyruğa kimseyi almaması gerektiğini söyledi. İşte buradaki bilgilendirme aşaması RabbitMQ’da Acknowledgement terimiyle geçerlidir.
Teknik açıklamasına dönelim.
Tüketici(consumer) kuyruktan gelen mesajı tükettiğinde göndericiye(producer) bu mesajın tüketildiğini veya bir problem oluştuğunu haber vermek isteyebilir. İşi biten bir mesajın rabbitmq kuyruğundan silinmesi gereklidir. Silinmediğinde kullanılmayan bir mesaj diskte boşa alan kaplıyor olacaktır. Mesajın tüketilmiş olduğunu gönderici(producer) öğrendiğinde diskteki mesajı silecektir. Ayrıca gönderici(producer) tarafından çıkan mesajlar tüketici(consumer) tarafından işlenirken tüketici(consumer) programı beklenmedik bir şekilde kapanabilir. Böyle durumlarda işleme alınan mesajların tamamlanmamış olma ihtimali gerçekleşeceğinden dolayı bu mesajların bilgisi “unacknowledged message” tabiriyle göndericiye(producer) verilir. Verilen bilgi neticesinde kuyruktan silme işlemi veya işlem başarıyla gerçekleşene kadar kuyrukta tutma işlemi devam eder.
İlgili kaynaklar:
https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html