RabbitMQ Deep Dive: Exchange Türleri, Routing Keys ve Queue Ayarları
RabbitMQ, mesaj kuyruklarının en popüler açık kaynak uygulamalarından biridir. AMQP (Advanced Message Queuing Protocol) üzerine inşa edilmiştir. Mesajlaşma mimarisinin kalbinde, üreticilerin (producers) mesajları doğrudan kuyruklara göndermediği, bunun yerine bir exchange (değiş-tokuş) üzerinden gönderdiği fikri yatar. Exchange, mesajları routing kurallarına göre uygun kuyruklara yönlendirir. Bu yazıda, RabbitMQ'nun dört temel exchange türünü (direct, fanout, topic, headers), routing key'leri, queue binding'leri ve mesaj kalıcılığı gibi kritik yapılandırmaları derinlemesine inceleyeceğiz.
1. Temel Kavramlar
-
Producer (Üretici): Mesajı gönderen uygulama.
-
Consumer (Tüketici): Mesajı alan ve işleyen uygulama.
-
Queue (Kuyruk): Mesajların depolandığı tampon. RabbitMQ'da mesajlar kuyruklarda saklanır.
-
Exchange (Değiş-Tokuş): Mesajları alan ve routing kurallarına göre kuyruklara yönlendiren bileşen. Üreticiler doğrudan kuyruğa değil, exchange'e gönderir.
-
Binding (Bağlama): Exchange ile kuyruk arasındaki ilişki. Bir exchange, bir veya daha fazla kuyruğa bağlanabilir.
-
Routing Key (Yönlendirme Anahtarı): Mesajın exchange tarafından nasıl yönlendirileceğini belirten bir anahtar. Binding'lerde de routing key kullanılır.
2. Exchange Türleri
RabbitMQ, dört ana exchange türü sunar. Her biri farklı routing ihtiyaçları için tasarlanmıştır.
A. Direct Exchange (Doğrudan Değiş-Tokuş)
-
Çalışma Mantığı: Mesaj, routing key ile gönderilir. Exchange, bu routing key ile birebir eşleşen binding routing key'ine sahip kuyruklara mesajı iletir.
-
Kullanım Senaryosu: Belirli bir mesajı belirli bir kuyruğa göndermek. Örneğin, hata seviyesine göre log mesajlarını farklı kuyruklara yönlendirmek.
-
Örnek:
-
Mesajın routing key'i
errorise,errorbinding key'ine sahip kuyruğa gider. -
Mesajın routing key'i
infoise,infobinding key'ine sahip kuyruğa gider.
-
csharp
// .NET'de Direct Exchange Kullanımı (MassTransit veya RabbitMQ.Client)
var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
// Direct exchange tanımla
channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct);
// Mesajı gönder (routing key = "error")
var body = Encoding.UTF8.GetBytes("Kritik hata oluştu!");
channel.BasicPublish(exchange: "direct_logs",
routingKey: "error",
basicProperties: null,
body: body);
B. Fanout Exchange (Yayın Değiş-Tokuşu)
-
Çalışma Mantığı: Routing key'i tamamen görmezden gelir. Mesajı, kendisine bağlı olan tüm kuyruklara kopyalar (broadcast). Bu, bir mesajı birden fazla tüketiciye iletmek için idealdir.
-
Kullanım Senaryosu: Bir olayı (event) birden çok servise bildirmek. Örneğin, yeni bir sipariş oluştuğunda, stok servisi, fatura servisi ve kargo servisinin hepsine aynı mesajı göndermek.
-
Örnek: Yeni sipariş bilgisi, fanout exchange'e gönderilir ve tüm bağlı kuyruklara dağıtılır.
csharp
// Fanout exchange tanımla
channel.ExchangeDeclare(exchange: "order_events", type: ExchangeType.Fanout);
// Mesajı gönder (routing key önemsiz, boş geçilebilir)
var body = Encoding.UTF8.GetBytes("Yeni sipariş oluşturuldu!");
channel.BasicPublish(exchange: "order_events",
routingKey: "",
basicProperties: null,
body: body);
C. Topic Exchange (Konu Değiş-Tokuşu)
-
Çalışma Mantığı: Direct exchange'e benzer, ancak routing key'lerinde wildcard (joker karakter) kullanımına izin verir. Bu, daha esnek routing kuralları oluşturmanızı sağlar.
-
*(yıldız) : Tam olarak bir kelimeyi temsil eder. -
#(kare) : Sıfır veya daha fazla kelimeyi temsil eder.
-
-
Kullanım Senaryosu: Çok boyutlu routing. Örneğin, "ülke.şehir.hata_seviyesi" gibi bir yapıda,
*.istanbul.*veyaturkiye.#gibi esnek filtrelemeler yapabilirsiniz. -
Örnek:
-
Mesaj routing key'i:
turkiye.istanbul.error -
Binding key
turkiye.*.error-> Eşleşir. -
Binding key
*.istanbul.*-> Eşleşir. -
Binding key
turkiye.#-> Eşleşir.
-
csharp
// Topic exchange tanımla
channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.Topic);
// Mesajı gönder (routing key = "turkiye.istanbul.error")
var body = Encoding.UTF8.GetBytes("İstanbul'dan kritik hata!");
channel.BasicPublish(exchange: "topic_logs",
routingKey: "turkiye.istanbul.error",
basicProperties: null,
body: body);
D. Headers Exchange (Başlık Değiş-Tokuşu)
-
Çalışma Mantığı: Routing key yerine, mesajın headers (başlık) alanlarındaki anahtar-değer çiftlerini kullanarak yönlendirme yapar. Routing key'den daha esnektir, çünkü birden fazla kritere göre eşleşme yapabilir.
-
x-matchParametresi:-
x-match = all: Tüm header'lar eşleşmelidir. -
x-match = any: Header'lardan en az biri eşleşmelidir.
-
-
Kullanım Senaryosu: Routing key'lerinin yetersiz kaldığı, çok boyutlu ve karmaşık routing kuralları gerektiğinde. Örneğin, bir mesajın
format: pdf,type: reportvepriority: highheader'larına sahip olması durumunda ilgili kuyruğa yönlendirilmesi.
csharp
// Headers exchange tanımla
channel.ExchangeDeclare(exchange: "headers_logs", type: ExchangeType.Headers);
// Mesajı gönder (headers ile)
var properties = channel.CreateBasicProperties();
properties.Headers = new Dictionary<string, object>
{
{ "format", "pdf" },
{ "type", "report" },
{ "x-match", "all" } // Tüm header'lar eşleşmeli
};
var body = Encoding.UTF8.GetBytes("PDF raporu");
channel.BasicPublish(exchange: "headers_logs",
routingKey: "",
basicProperties: properties,
body: body);
3. Queue Ayarları (Mesaj Kalıcılığı ve Diğerleri)
Kuyruklar, mesajların nasıl saklanacağını ve yönetileceğini belirleyen önemli parametrelere sahiptir.
A. Durable (Kalıcı) vs Transient (Geçici)
-
Durable (Kalıcı): Kuyruk, RabbitMQ yeniden başlatılsa bile varlığını sürdürür. Disk üzerinde saklanır.
-
Transient (Geçici): Kuyruk, yalnızca RabbitMQ çalışırken var olur. Sunucu yeniden başlatılırsa kuyruk silinir.
csharp
// Kalıcı (durable) kuyruk oluşturma
channel.QueueDeclare(queue: "order_queue",
durable: true, // Kalıcı
exclusive: false,
autoDelete: false,
arguments: null);
B. Message Durability (Mesaj Kalıcılığı)
-
Mesaj kalıcılığı, kuyruğun kalıcı olmasından farklıdır. Kalıcı bir kuyrukta bile, mesaj
persistentolarak işaretlenmezse, sunucu yeniden başlatıldığında mesaj kaybolur. -
Persistent(Kalıcı) Mesaj: RabbitMQ yeniden başlatılsa bile mesaj diskte saklanır ve kaybolmaz. -
Transient(Geçici) Mesaj: Sunucu yeniden başlatılırsa mesaj kaybolur. Daha hızlıdır, ancak veri kaybı riski vardır.
csharp
// Kalıcı mesaj gönderme
var properties = channel.CreateBasicProperties();
properties.Persistent = true; // Mesaj kalıcı olsun!
channel.BasicPublish(exchange: "order_events",
routingKey: "order.created",
basicProperties: properties,
body: body);
C. Auto-Delete (Otomatik Silme)
Kuyruğa bağlı son tüketici de bağlantısını kestiğinde, kuyruğun otomatik olarak silinmesini sağlar. Genellikle geçici (temporary) kuyruklar için kullanılır.
D. TTL (Time-To-Live) - Mesaj Yaşam Süresi
Bir mesajın kuyrukta ne kadar süre kalabileceğini belirler. Süre dolduğunda mesaj otomatik olarak silinir.
csharp
// Kuyruk seviyesinde TTL (tüm mesajlar için)
var args = new Dictionary<string, object>
{
{ "x-message-ttl", 60000 } // 60 saniye
};
channel.QueueDeclare(queue: "order_queue",
durable: true,
exclusive: false,
autoDelete: false,
arguments: args);
// Mesaj seviyesinde TTL (belirli bir mesaj için)
var properties = channel.CreateBasicProperties();
properties.Expiration = "60000"; // 60 saniye (string olarak gönderilir)
E. Dead Letter Exchange (Ölü Mesaj Değiş-Tokuşu)
İşlenemeyen (reddedilen, TTL'si dolan, kuyruk boyutu aşılan) mesajların yönlendirileceği bir exchange tanımlar. Bu, hata yönetimi ve izleme için çok kullanışlıdır.
csharp
var args = new Dictionary<string, object>
{
{ "x-dead-letter-exchange", "dlx_exchange" },
{ "x-dead-letter-routing-key", "failed" }
};
channel.QueueDeclare(queue: "order_queue",
durable: true,
exclusive: false,
autoDelete: false,
arguments: args);
4. Binding (Bağlama) İşlemleri
Binding, exchange ile kuyruk arasındaki ilişkiyi kurar.
csharp
// Direct exchange ile binding
channel.QueueBind(queue: "error_queue",
exchange: "direct_logs",
routingKey: "error");
// Topic exchange ile binding (wildcard)
channel.QueueBind(queue: "turkiye_logs",
exchange: "topic_logs",
routingKey: "turkiye.#");
// Headers exchange ile binding
channel.QueueBind(queue: "pdf_report_queue",
exchange: "headers_logs",
routingKey: "",
arguments: new Dictionary<string, object>
{
{ "format", "pdf" },
{ "x-match", "all" }
});
5. .NET ile RabbitMQ Entegrasyonu
.NET ekosisteminde RabbitMQ ile çalışmanın iki ana yolu vardır:
A. RabbitMQ.Client (Ham İstemci)
En alt seviye, en esnek yöntemdir. Yukarıdaki örneklerin çoğu bu kütüphane ile yapılmıştır. NuGet: RabbitMQ.Client
B. MassTransit (Yüksek Seviye Kütüphane)
MassTransit, RabbitMQ üzerinde soyutlama (abstraction) sağlayan, CQRS, MediatR, Outbox gibi desenleri de destekleyen popüler bir mesajlaşma kütüphanesidir.
csharp
// MassTransit ile RabbitMQ yapılandırması
builder.Services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.ReceiveEndpoint("order_queue", e =>
{
e.ConfigureConsumer<OrderConsumer>(context);
});
});
});
6. Exchange ve Queue Seçim Rehberi
| İhtiyaç | Önerilen Exchange | Açıklama |
|---|---|---|
| Mesajı tam olarak bir kuyruğa yönlendirme | Direct | Örneğin, log seviyesine göre yönlendirme (error, warn, info). |
| Mesajı tüm kuyruklara gönderme (broadcast) | Fanout | Örneğin, bir olayı tüm servislere bildirme. |
| Esnek, wildcard'lı yönlendirme | Topic | Örneğin, ülke-şehir-hata seviyesine göre filtreleme. |
| Çok boyutlu, header tabanlı yönlendirme | Headers | Örneğin, mesaj tipi, format ve önceliğe göre yönlendirme. |
| Yüksek veri güvenliği gerekiyorsa | Durable Queue + Persistent Message | Mesajların diskte saklanması ve kaybolmaması için. |
| İşlenemeyen mesajları yönetme | Dead Letter Exchange | Hata mesajlarını toplama ve izleme için. |
Sonuç:
RabbitMQ'nun gücü, esnek exchange ve routing mekanizmasından gelir. Direct ile basit yönlendirme, Fanout ile yayın, Topic ile esnek filtreleme ve Headers ile çok boyutlu yönlendirme yapabilirsiniz. Doğru exchange türünü seçmek, mesajlaşma mimarinizin performansı ve ölçeklenebilirliği için kritiktir.
Unutmayın:
-
Kalıcılık (Durability) veri kaybını önlemek için önemlidir.
-
Dead Letter Exchange ile başarısız mesajları izleyin.
-
MassTransit gibi kütüphaneler, RabbitMQ ile çalışmayı çok daha kolay hale getirir.
RabbitMQ'yu doğru yapılandırarak, uygulamalarınız arasında sağlam, esnek ve güvenilir bir mesajlaşma altyapısı kurabilirsiniz.