Skip to main content
Yazılım Geliştirme

RabbitMQ ile Mesaj Kuyruğu Mimarisi

Mart 06, 2026 7 dk okuma 17 views Raw
Ayrıca mevcut: en
RabbitMQ ile mesaj kuyruğu mimarisi sistem diyagramı
İçindekiler

Mesaj Kuyruğu Mimarisi Nedir?

Modern yazılım sistemlerinde bileşenler arasındaki iletişim, uygulamaların ölçeklenebilirliği ve güvenilirliği açısından kritik bir rol oynar. Mesaj kuyruğu mimarisi, bu iletişimi asenkron bir yapıya taşıyarak sistemlerin birbirinden bağımsız çalışmasını sağlar. Bir bileşen mesaj üretir, diğer bileşen ise bu mesajı hazır olduğunda tüketir. Bu süreçte mesaj broker adı verilen bir ara katman devreye girer.

Geleneksel senkron iletişimde bir servis diğerine istek gönderir ve yanıt bekler. Bu yaklaşım, yüksek trafik altında darboğaz oluşturur ve bir servisin çökmesi tüm zinciri etkiler. Mesaj kuyruğu mimarisi bu sorunu ortadan kaldırarak gevşek bağlı (loosely coupled) bir sistem tasarımı sunar.

RabbitMQ, bu alanda en yaygın kullanılan açık kaynaklı mesaj broker çözümlerinden biridir. Erlang diliyle yazılmış olan RabbitMQ, AMQP protokolünü temel alır ve yüksek performanslı, güvenilir mesaj iletimi sağlar.

RabbitMQ Temel Kavramları

RabbitMQ ekosistemini anlamak için öncelikle temel kavramları bilmek gerekir. Bu kavramlar, mesajların nasıl üretildiğini, yönlendirildiğini ve tüketildiğini açıklar.

Producer ve Consumer

Producer, mesaj üreten uygulamadır. Örneğin bir e-ticaret sisteminde sipariş oluşturulduğunda sipariş servisi bir mesaj üretir. Consumer ise bu mesajı alan ve işleyen uygulamadır. Bildirim servisi bu mesajı alarak kullanıcıya e-posta gönderebilir.

Queue (Kuyruk)

Queue, mesajların geçici olarak depolandığı yapıdır. Mesajlar FIFO (First In, First Out) prensibiyle işlenir. Kuyruklar dayanıklı (durable) olarak tanımlandığında RabbitMQ yeniden başlatılsa bile mesajlar korunur. Kuyrukların temel özellikleri şunlardır:

  • Durable: Broker yeniden başlatıldığında kuyruk korunur
  • Exclusive: Yalnızca tek bir bağlantı tarafından kullanılır
  • Auto-delete: Son consumer ayrıldığında otomatik silinir
  • TTL (Time to Live): Mesajların kuyrukta kalma süresi belirlenir

Exchange

Exchange, mesajların kuyruklara yönlendirilmesinden sorumlu bileşendir. Producer mesajı doğrudan kuyruğa değil, exchange'e gönderir. Exchange ise tanımlanan kurallara göre mesajı ilgili kuyruklara dağıtır.

Binding

Binding, exchange ile queue arasındaki bağlantıyı tanımlar. Bir routing key kullanılarak hangi mesajların hangi kuyruğa gideceği belirlenir. Bu yapı sayesinde karmaşık yönlendirme senaryoları kolayca uygulanabilir.

Exchange Türleri ve Kullanım Senaryoları

RabbitMQ dört farklı exchange türü sunar. Her biri farklı mesaj yönlendirme stratejileri için tasarlanmıştır.

Direct Exchange

Direct exchange, mesajları routing key ile eşleşen kuyruklara yönlendirir. Birebir eşleşme gerektirir. Örneğin bir log sisteminde "error" routing key'i ile gönderilen mesajlar yalnızca hata kuyruğuna iletilir.

channel.ExchangeDeclare("direct-logs", ExchangeType.Direct);
channel.BasicPublish("direct-logs", "error", null, body);

Fanout Exchange

Fanout exchange, gelen mesajı kendisine bağlı tüm kuyruklara iletir. Routing key dikkate alınmaz. Bu tür, broadcast senaryoları için idealdir. Örneğin bir fiyat güncelleme sistemi tüm abonelere aynı mesajı gönderebilir.

channel.ExchangeDeclare("broadcast", ExchangeType.Fanout);
channel.BasicPublish("broadcast", "", null, body);

Topic Exchange

Topic exchange, routing key üzerinde desen eşleştirmesi yapar. Joker karakterler kullanılarak esnek yönlendirme kuralları tanımlanır. Yıldız (*) tek bir kelimeyi, diyez (#) ise sıfır veya daha fazla kelimeyi eşleştirir.

// "order.created" ve "order.updated" mesajları bu kuyruğa gelir
channel.QueueBind(queueName, "topic-exchange", "order.*");

// Tüm log mesajları bu kuyruğa gelir
channel.QueueBind(queueName, "topic-exchange", "log.#");

Headers Exchange

Headers exchange, routing key yerine mesaj başlıklarını (headers) kullanarak yönlendirme yapar. Birden fazla koşula dayalı karmaşık yönlendirme senaryolarında tercih edilir. x-match parametresi "all" veya "any" değerlerini alarak tüm başlıkların veya herhangi birinin eşleşmesini koşul olarak belirler.

Dead Letter Queue (DLQ) Mekanizması

Gerçek dünya uygulamalarında mesajların işlenememesi kaçınılmaz bir durumdur. Dead Letter Queue, işlenemeyen mesajların kaybolmasını önleyen kritik bir mekanizmadır. Bir mesaj aşağıdaki durumlarda dead letter queue'ya yönlendirilir:

  • Consumer tarafından reddedildiğinde (nack veya reject)
  • Mesajın TTL süresi dolduğunda
  • Kuyruk maksimum kapasitesine ulaştığında

DLQ yapılandırması kuyruk tanımlanırken gerçekleştirilir:

var args = new Dictionary<string, object>
{
    { "x-dead-letter-exchange", "dlx-exchange" },
    { "x-dead-letter-routing-key", "dead-letter" }
};
channel.QueueDeclare("main-queue", true, false, false, args);

Bu yapı sayesinde başarısız mesajlar analiz edilebilir, yeniden işlenebilir veya manuel müdahale için bekletilebilir. Üretim ortamlarında DLQ kullanmamak ciddi veri kaybına yol açabilir.

RabbitMQ ve .NET Entegrasyonu

.NET ekosisteminde RabbitMQ entegrasyonu RabbitMQ.Client NuGet paketi ile sağlanır. Bu kütüphane, RabbitMQ'nun tüm özelliklerini .NET uygulamalarında kullanmanıza olanak tanır.

Bağlantı ve Kanal Yönetimi

RabbitMQ ile iletişim kurmak için önce bir bağlantı (connection), ardından bir kanal (channel) oluşturulur. Bağlantılar TCP düzeyindedir ve maliyetlidir; bu nedenle kanallar çoğaltılarak tek bir bağlantı üzerinden birden fazla işlem gerçekleştirilir.

var factory = new ConnectionFactory
{
    HostName = "localhost",
    UserName = "guest",
    Password = "guest",
    Port = 5672
};

using var connection = await factory.CreateConnectionAsync();
using var channel = await connection.CreateChannelAsync();

Mesaj Gönderme

Mesaj gönderirken mesajın kalıcılığını (persistence) sağlamak önemlidir. Kalıcı mesajlar diske yazılarak broker çökmelerinde korunur.

var properties = new BasicProperties
{
    Persistent = true,
    ContentType = "application/json"
};

var message = JsonSerializer.Serialize(orderEvent);
var body = Encoding.UTF8.GetBytes(message);

await channel.BasicPublishAsync("order-exchange", "order.created", 
    mandatory: true, basicProperties: properties, body: body);

Mesaj Tüketme

Consumer tarafında mesajların güvenilir şekilde işlenmesi için manual acknowledgement kullanılmalıdır. Bu sayede mesaj yalnızca başarıyla işlendiğinde kuyruktan kaldırılır.

var consumer = new AsyncEventingBasicConsumer(channel);
consumer.ReceivedAsync += async (model, ea) =>
{
    try
    {
        var body = ea.Body.ToArray();
        var message = Encoding.UTF8.GetString(body);
        // Mesajı işle
        await ProcessMessageAsync(message);
        await channel.BasicAckAsync(ea.DeliveryTag, multiple: false);
    }
    catch (Exception)
    {
        await channel.BasicNackAsync(ea.DeliveryTag, 
            multiple: false, requeue: true);
    }
};

await channel.BasicConsumeAsync("order-queue", 
    autoAck: false, consumer: consumer);

Yüksek Erişilebilirlik ve Kümeleme

Üretim ortamlarında tek bir RabbitMQ düğümü yeterli olmaz. Yüksek erişilebilirlik için kümeleme (clustering) yapılandırması gereklidir.

Quorum Queues

RabbitMQ 3.8 ile tanıtılan Quorum Queues, klasik aynalı kuyrukların (mirrored queues) yerini almıştır. Raft konsensüs algoritmasını kullanarak veri tutarlılığını garanti eder. Quorum kuyrukları şu avantajları sunar:

  • Otomatik lider seçimi ile kesintisiz hizmet
  • Veri kaybına karşı güçlü koruma
  • Daha öngörülebilir performans karakteristikleri
  • Poison message handling desteği

Küme Yapılandırması

Üretim ortamında en az üç düğümlü bir küme önerilir. Bu yapıda bir düğüm çökse bile sistem çalışmaya devam eder. Yük dengeleyici (load balancer) kullanılarak istemciler kümedeki düğümlere dağıtılır.

Performans Optimizasyonu

RabbitMQ performansını artırmak için çeşitli optimizasyon teknikleri uygulanabilir.

Prefetch Count

Prefetch count, bir consumer'ın aynı anda işleyebileceği mesaj sayısını belirler. Bu değer doğru ayarlanmazsa ya consumer boşta kalır ya da aşırı yüklenir.

// Consumer başına 10 mesaj prefetch
await channel.BasicQosAsync(prefetchSize: 0, 
    prefetchCount: 10, global: false);

Batch Publishing

Çok sayıda mesaj gönderirken publisher confirms ile birlikte batch publishing kullanmak verimlilik sağlar. Her mesaj için ayrı ayrı onay beklemek yerine bir grup mesaj gönderdikten sonra toplu onay beklenir.

Lazy Queues

Büyük kuyruklar için lazy queue modu tercih edilebilir. Bu modda mesajlar doğrudan diske yazılır ve bellek tüketimi minimuma indirilir. Özellikle milyonlarca mesaj barındıran kuyruklarda bu yaklaşım bellek taşmasını önler.

İzleme ve Yönetim

RabbitMQ, yerleşik bir yönetim arayüzü sunar. Bu arayüz üzerinden kuyrukların durumu, mesaj oranları, bağlantılar ve kanallar izlenebilir. Management plugin varsayılan olarak 15672 portunda çalışır.

Üretim ortamlarında ek olarak Prometheus ve Grafana entegrasyonu yapılarak detaylı metrikler toplanmalıdır. İzlenmesi gereken kritik metrikler şunlardır:

  • Kuyruk derinliği (queue depth) ve büyüme hızı
  • Mesaj publish ve consume oranları
  • Consumer sayısı ve durumu
  • Bellek ve disk kullanımı
  • Bağlantı ve kanal sayıları

En İyi Uygulamalar

RabbitMQ ile güvenilir bir mesaj kuyruğu mimarisi kurarken dikkat edilmesi gereken temel prensipler vardır.

Mesaj kuyruğu mimarisi, doğru uygulandığında sisteminizin ölçeklenebilirliğini ve dayanıklılığını dramatik şekilde artırır. Ancak yanlış yapılandırma, çözmekten daha fazla sorun yaratabilir.
  • Her zaman durable queue ve persistent message kullanın
  • Manual acknowledgement tercih edin, auto-ack risklidir
  • Dead letter queue yapılandırmasını ihmal etmeyin
  • İdempotent consumer tasarlayın; aynı mesaj birden fazla kez işlenebilir
  • Mesaj boyutunu küçük tutun; büyük veriler için referans gönderin
  • Bağlantıları yeniden kullanın, her işlem için yeni bağlantı açmayın
  • Üretim ortamında mutlaka kümeleme yapılandırın
  • İzleme ve alarm sistemlerini kurun

Sonuç

RabbitMQ ile mesaj kuyruğu mimarisi, mikroservis tabanlı sistemlerde güvenilir ve ölçeklenebilir iletişim sağlamanın kanıtlanmış bir yoludur. Exchange türlerini doğru seçmek, dead letter queue mekanizmasını yapılandırmak ve performans optimizasyonlarını uygulamak başarılı bir implementasyonun temel taşlarıdır.

.NET ekosistemindeki güçlü kütüphane desteği sayesinde RabbitMQ entegrasyonu hızlı ve etkili bir şekilde gerçekleştirilebilir. Quorum queue'lar ve kümeleme ile yüksek erişilebilirlik sağlanarak üretim ortamlarında kesintisiz hizmet sunulabilir. Doğru izleme ve yönetim pratikleriyle birlikte RabbitMQ, mesaj odaklı mimarinizin güvenilir omurgası haline gelir.

Bu yazıyı paylaş