TEMEL
Exchange Tipleri
Exchange, mesajları queue'lara yönlendiren bileşendir — bir nevi "trafik polisi". Kendisi mesaj saklamaz; kurallara bakıp "bu mesaj şu queue'ya gitsin" der.
3.1 Direct Exchange — "Tam Adrese Teslim"
En basit tip. Mesajın routing key'i, queue'nun binding key'i ile birebir eşleşiyorsa mesaj o queue'ya gider. Eşleşme yoksa mesaj sessizce kaybolur (bunu önlemek için mandatory: true ayarlanabilir — eşleşme yoksa mesaj geri döner).
Benzetme: Posta kutusuna isim yaz. Sadece o isme gelen mektuplar düşer.
| Ne Zaman Kullan | Ne Zaman Kullanma |
|---|---|
| Mesajı bilinen tek bir queue'ya göndermek | Aynı mesajı birden fazla yere göndermek |
| 1 gönderici → 1 alıcı basit iletişim | Routing key'de joker karakter (*, #) gerekiyorsa |
| Cevap beklenen istek-yanıt akışlarında (request → response queue) | "Herkese duyur" senaryolarında (Fanout daha uygun) |
.NET — Direct Exchange
// Direct exchange declare
await channel.ExchangeDeclareAsync("orders.direct", ExchangeType.Direct, durable: true);
// Queue declare & bind (key = "order.created")
await channel.QueueDeclareAsync("order-processing", durable: true, exclusive: false, autoDelete: false);
await channel.QueueBindAsync("order-processing", "orders.direct", routingKey: "order.created");
// Publish — routing key birebir eşleşmeli
await channel.BasicPublishAsync(
exchange: "orders.direct",
routingKey: "order.created", // ← "order.created" bind'ına exact match
body: messageBody);
3.2 Fanout Exchange — "Herkese Duyuru"
Routing key'i tamamen yok sayar. Exchange'e bind olan tüm queue'lara aynı mesajı gönderir. Kaç queue bind olursa olsun, hepsine aynı mesaj ulaşır.
Benzetme: Hoparlörden anons. Kim bağlıysa duysun — seçici değil.
| Ne Zaman Kullan | Ne Zaman Kullanma |
|---|---|
| Aynı event'i birden fazla servise iletmek (email + analytics + audit) | Mesajın sadece belirli alıcılara gitmesi gerektiğinde |
| "Bir şey oldu, ilgilenen herkes duysun" duyuruları | Alıcıların çoğu mesajı işlemeyecekse (gereksiz yük) |
| Chat odası gibi: herkese aynı mesaj | Mesajları filtrelemek gerekiyorsa → Topic kullan |
.NET — Fanout Exchange (Broadcast)
// Fanout exchange — routing key ignored
await channel.ExchangeDeclareAsync(
exchange: "user.signup.fanout",
type: ExchangeType.Fanout,
durable: true);
// Her consumer kendi queue'sunu bind eder
await channel.QueueDeclareAsync("signup-email", durable: true, exclusive: false, autoDelete: false);
await channel.QueueDeclareAsync("signup-analytics", durable: true, exclusive: false, autoDelete: false);
await channel.QueueDeclareAsync("signup-audit", durable: true, exclusive: false, autoDelete: false);
await channel.QueueBindAsync("signup-email", "user.signup.fanout", routingKey: ""); // key ignored
await channel.QueueBindAsync("signup-analytics", "user.signup.fanout", routingKey: ""); // key ignored
await channel.QueueBindAsync("signup-audit", "user.signup.fanout", routingKey: ""); // key ignored
// Publish — routing key boş olabilir, fanout yok sayar
await channel.BasicPublishAsync("user.signup.fanout", routingKey: "", body: body);
3.3 Topic Exchange — "Akıllı Filtreleme"
Direct gibi routing key kullanır ama wildcard pattern destekler. Key noktalarla ayrılmış kelimelerden oluşur (ör: order.eu.created). Queue'lar pattern ile bind olur:
*→ tam 1 kelime eşleşir#→ 0 veya daha fazla kelime eşleşir
Benzetme: E-posta filtresi. "order ile başlayan VE created ile biten tüm mailleri göster."
Pattern Eşleşme Tablosu:
| Pattern | Açıklama | Eşleşen Örnekler |
|---|---|---|
order.*.created |
* = tam 1 kelime |
order.eu.created · order.us.created · order.created |
payment.# |
# = 0 veya daha fazla kelime |
payment · payment.success · payment.eu.visa.success |
#.error |
Sonu "error" olan her şey | app.service.error · error |
*.*.critical |
3 segment, sonu critical | app.db.critical · app.critical |
| Ne Zaman Kullan | Ne Zaman Kullanma |
|---|---|
Kategori bazlı yönlendirme (ör: sipariş.avrupa.oluşturuldu) |
Tek bir alıcıya gidecekse (Direct daha hızlı) |
| Farklı alıcılar farklı konuları dinleyecekse | Tüm mesajlar herkese gidecekse (Fanout daha basit) |
Log yönlendirme: logs.production.error → sadece ops ekibi |
Joker desenler hata ayıklamayı zorlaştırıyorsa |
.NET — Topic Exchange Declare & Publish
// Exchange declare
await channel.ExchangeDeclareAsync(
exchange: "domain.events",
type: ExchangeType.Topic,
durable: true,
autoDelete: false);
// Queue declare & bind
await channel.QueueDeclareAsync("order-notifications", durable: true, exclusive: false, autoDelete: false);
await channel.QueueBindAsync("order-notifications", "domain.events", routingKey: "order.*.created");
// Publish
var body = JsonSerializer.SerializeToUtf8Bytes(orderEvent);
var props = new BasicProperties
{
ContentType = "application/json",
DeliveryMode = DeliveryModes.Persistent,
MessageId = Guid.NewGuid().ToString()
};
await channel.BasicPublishAsync(
exchange: "domain.events",
routingKey: "order.eu.created", // matches "order.*.created"
mandatory: true,
basicProperties: props,
body: body);
3.4 Headers Exchange — "Çoklu Kriter"
Routing key'i tamamen yok sayar. Bunun yerine mesajın header'larına bakar. x-match: all (tüm header'lar eşleşmeli) veya x-match: any (herhangi biri yeterli) modlarında çalışır.
Benzetme: Dosya sınıflandırma sistemi. "format=pdf VE department=finance olan dokümanları bu klasöre koy."
| Ne Zaman Kullan | Ne Zaman Kullanma |
|---|---|
| Birden fazla özelliğe göre yönlendirme gerekiyor (format + departman + bölge) | Basit key eşleşmesi yeterliyse (Direct/Topic daha hızlı) |
| Routing key yapısı yetersiz kalıyorsa (tek string'e sığmayan kriterler) | Yüksek mesaj hacmi — header karşılaştırma daha yavaş |
| "PDF + finans departmanı + Avrupa" gibi çoklu filtre | Topic'in joker desenleri ihtiyacı karşılıyorsa |
Karşılaştırma: Hangi Exchange'i Seçmeliyim?
4 exchange tipini tek bakışta karşılaştır:
Karar Tablosu
| Senaryo | Exchange Tipi | Neden | Gerçek Hayat |
|---|---|---|---|
| Mesajı tek bir queue'ya yönlendir | Direct | Exact match, basit ve hızlı | Order → order-processing queue |
| Aynı mesajı tüm subscriber'lara gönder | Fanout | Routing key gereksiz, herkese broadcast | User signup → email + analytics + audit |
| Hiyerarşik routing (namespace.entity.action) | Topic | Wildcard patterns ile esnek filtreleme | logs.production.error → ops team queue |
| Multi-attribute routing (header bazlı) | Headers | Routing key yetersiz, birden fazla kriter | Content-type + priority bazlı routing |
| Load distribution (sharding) | Consistent Hash (plugin) | Mesajları N queue'ya dengeli dağıt | High-throughput ingestion pipeline |
Dikkat: Topic exchange, direct'e göre biraz daha fazla CPU kullanır (pattern matching). Ancak fark genelde ihmal edilebilir düzeydedir. Routing karmaşıklığı artacaksa baştan topic exchange tercih edin — sonradan geçiş zordur.
Anti-Pattern: God Exchange — Tek bir fanout exchange'e tüm event'leri publish edip, consumer tarafında filtreleme yapmak. Bu, her consumer'ın tüm mesajları alıp %90'ını drop etmesi demektir → bandwidth ve CPU israfı. Exchange'leri domain boundary'lerine göre ayırın.
Gerçek hayat senaryosu: Bir chat uygulamasında, her oda (room) için bir fanout exchange oluşturulur. Odaya katılan her kullanıcı kendi exclusive queue'sunu bu exchange'e bind eder. Mesaj gönderildiğinde tüm katılımcılara aynı anda ulaşır.