← Kursa Dön
📄 Text · 30 min

RabbitMQ Temelleri

RabbitMQ, AMQP (Advanced Message Queuing Protocol) protokolünü implemente eden, açık kaynaklı ve en yaygın kullanılan message broker'lardan biridir. Erlang dili ile yazılmıştır ve yüksek güvenilirlik, esneklik ve geniş dil desteği sunar. Bu derste RabbitMQ'nun temel kavramlarını, exchange türlerini, kuyruk mekanizmalarını ve mesaj yaşam döngüsünü detaylıca inceleyeceğiz.

AMQP Protokolü

AMQP (Advanced Message Queuing Protocol), mesaj aracıları için tasarlanmış açık standart bir uygulama katmanı protokolüdür. AMQP şunları tanımlar:

  • Mesaj formatı: Header, properties ve body bölümlerinden oluşan standart yapı

  • Exchange ve Queue mekanizmaları: Mesajların nasıl yönlendirileceği

  • Connection ve Channel modeli: TCP bağlantısı üzerinden çoklu sanal kanallar

  • Güvenilirlik mekanizmaları: Acknowledgement, transaction, persistence

AMQP'nin önemli bir özelliği wire-level protocol olmasıdır — yani farklı dillerde yazılmış uygulamalar sorunsuz iletişim kurabilir. Java producer'ınız Python consumer'a mesaj gönderebilir.

┌─────────────┐     TCP Connection
│  Application │ ─────────────────────▶ ┌──────────────┐
│              │   Channel 1 ──────────▶│              │
│  (Producer/  │   Channel 2 ──────────▶│  RabbitMQ    │
│   Consumer)  │   Channel 3 ──────────▶│  Broker      │
│              │                        │              │
└─────────────┘                        └──────────────┘

Connection: Uygulama ile broker arasındaki TCP bağlantısıdır. Maliyetli bir işlemdir (TCP handshake, TLS).

Channel: Bir connection içindeki hafif sanal bağlantıdır. Her thread kendi channel'ını kullanır. Connection oluşturmak pahalı olduğu için, tek bir connection üzerinden birçok channel açılır.

RabbitMQ Mimarisi: Exchange → Binding → Queue

RabbitMQ'da mesaj akışı şu şekilde çalışır:

Producer ──msg──▶ Exchange ──routing──▶ Queue ──msg──▶ Consumer
                     │         ▲
                     └─binding─┘
                    (routing key + pattern)
  1. Producer mesajı bir exchange'e gönderir (doğrudan kuyruğa değil).

  2. Exchange, mesajın routing key'ine ve binding kurallarına bakarak mesajı uygun kuyruğa/kuyruklara yönlendirir.

  3. Queue mesajı saklar ve consumer'a teslim eder.

Bu üç katmanlı mimari büyük esneklik sağlar: producer kuyruğu bilmez, exchange yönlendirme mantığını soyutlar.

Exchange Türleri

RabbitMQ dört farklı exchange türü sunar:

1. Direct Exchange

Mesajın routing key'i ile queue'nun binding key'i tam eşleştiğinde mesaj o kuyruğa yönlendirilir. En basit ve en yaygın kullanılan türdür.

Producer ──routing_key="order.created"──▶ [Direct Exchange]
                                              │
                    binding_key="order.created" ──▶ Queue-A ✓
                    binding_key="payment.done"  ──▶ Queue-B ✗

Kullanım alanı: Belirli bir kuyruğa hedefli mesaj gönderme. Örneğin, hata loglarını "error-queue"ya, bilgi loglarını "info-queue"ya yönlendirme.

2. Topic Exchange

Pattern matching ile yönlendirme yapar. Routing key nokta (.) ile ayrılmış kelimelerden oluşur. Binding key'de iki özel karakter kullanılır:

  • * (yıldız): Tam olarak bir kelimeyle eşleşir

  • # (diyez): Sıfır veya daha fazla kelimeyle eşleşir

Routing key: "order.eu.created"

Binding "order.*.created"   → ✓ eşleşir (eu tek kelime)
Binding "order.#"           → ✓ eşleşir (eu.created sıfır veya daha fazla)
Binding "order.us.created"  → ✗ eşleşmez (us ≠ eu)
Binding "#.created"         → ✓ eşleşir

Kullanım alanı: Hiyerarşik routing. Örneğin log.error.payment, log.warn.auth gibi yapılarla farklı aboneleri farklı log seviyelerine yönlendirme.

3. Fanout Exchange

Routing key'i tamamen yok sayar ve mesajı kendisine bağlı tüm kuyruklara kopyalar. Klasik broadcast mekanizmasıdır.

Producer ──▶ [Fanout Exchange] ──▶ Queue-A (kopya)
                                ──▶ Queue-B (kopya)
                                ──▶ Queue-C (kopya)

Kullanım alanı: Bir olayın birden fazla servise bildirilmesi gerektiğinde. Örneğin, kullanıcı kaydı sonrası e-posta servisi, analitik servisi ve CRM servisi hepsine bildirim.

4. Headers Exchange

Routing key yerine mesajın header değerlerine göre yönlendirme yapar. Binding'de x-match parametresi ile eşleşme kuralı belirlenir:

  • x-match = all: Tüm belirtilen header'lar eşleşmeli (AND)

  • x-match = any: Herhangi bir header eşleşmeli (OR)

Message headers: {format: "pdf", type: "report"}

Binding {x-match: all, format: "pdf", type: "report"} → ✓ eşleşir
Binding {x-match: any, format: "pdf", type: "invoice"} → ✓ eşleşir (format eşleşti)
Binding {x-match: all, format: "csv", type: "report"}  → ✗ eşleşmez (format farklı)

Kullanım alanı: Karmaşık yönlendirme kuralları gerektiğinde, routing key yetmediğinde kullanılır. Pratikte en az kullanılan exchange türüdür.

Queue Özellikleri

Queue (kuyruk), mesajların FIFO (First-In-First-Out) sırasıyla depolandığı yapıdır. Önemli özellikleri:

  • Durable: Broker yeniden başladığında kuyruk kaybolmaz. Production ortamında mutlaka durable=true olmalıdır.

  • Exclusive: Yalnızca bir connection tarafından kullanılabilir, connection kapanınca kuyruk silinir. Geçici, özel kullanım için.

  • Auto-delete: Son consumer ayrıldığında kuyruk otomatik silinir.

  • TTL (Time-to-Live): Mesajların kuyrukta ne kadar süre kalacağını belirler. Süresi dolan mesajlar otomatik silinir veya dead letter queue'ya yönlendirilir.

  • Max-length: Kuyrukta tutulabilecek maksimum mesaj sayısı. Aşıldığında en eski mesajlar düşürülür veya dead letter queue'ya gönderilir.

Routing Key ve Binding

Routing key, producer'ın mesajla birlikte gönderdiği bir string'dir. Exchange, bu key'i kullanarak mesajı hangi kuyruğa yönlendireceğine karar verir.

Binding, exchange ile queue arasındaki bağlantı kuralıdır. Bir queue birden fazla exchange'e, bir exchange birden fazla queue'ya bind edilebilir.

// Direct exchange ile binding
channel.queueBind("email-queue", "notification-exchange", "email");
channel.queueBind("sms-queue", "notification-exchange", "sms");

// Producer routing key ile mesaj gönderir
channel.basicPublish("notification-exchange", "email", null, message.getBytes());
// → email-queue'ya gider

channel.basicPublish("notification-exchange", "sms", null, message.getBytes());
// → sms-queue'ya gider

Acknowledgement (Mesaj Onayı)

RabbitMQ'da mesaj tesliminin güvenilirliği acknowledgement mekanizmasıyla sağlanır:

Consumer acknowledgement: Consumer, mesajı başarıyla işlediğinde broker'a ACK gönderir. ACK gelene kadar mesaj kuyruktan silinmez.

  • basicAck: Mesaj başarıyla işlendi, kuyruktan silinebilir.

  • basicNack: Mesaj işlenemedi, tekrar kuyruğa konabilir (requeue) veya düşürülebilir.

  • basicReject: Tek mesaj için nack — benzer şekilde requeue veya drop.

// Manuel acknowledgement
channel.basicConsume("orders", false, (consumerTag, delivery) -> {
    try {
        processOrder(delivery.getBody());
        channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
    } catch (Exception e) {
        // Mesajı tekrar kuyruğa koy (requeue=true)
        channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, true);
    }
}, consumerTag -> {});

Publisher confirm: Producer tarafında da onay alınabilir. Broker mesajı diske yazıp kuyruğa ekledikten sonra producer'a confirm gönderir. Bu, mesajın broker'a ulaştığından emin olmanızı sağlar.

Dead Letter Queue (DLQ)

Dead Letter Queue, işlenemeyen veya reddedilen mesajların yönlendirildiği özel bir kuyruktur. Bir mesaj şu durumlarda "dead letter" olur:

  1. Consumer mesajı reject eder ve requeue=false belirtir

  2. Mesajın TTL'i dolar

  3. Kuyruk maksimum uzunluğa ulaşır ve eski mesajlar düşürülür

// DLQ yapılandırması
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx-exchange");
args.put("x-dead-letter-routing-key", "dead-orders");
args.put("x-message-ttl", 60000); // 60 saniye TTL

channel.queueDeclare("orders", true, false, false, args);

DLQ stratejisi, production sistemlerinde olmazsa olmaz bir bileşendir. İşlenemeyen mesajları kaybetmek yerine DLQ'ya yönlendirip, sonra analiz ederek sorunu çözmek en güvenilir yaklaşımdır. Monitoring araçlarıyla DLQ'daki mesaj sayısını izlemek, sistemdeki sorunları erken tespit etmenizi sağlar.

RabbitMQ Management UI

RabbitMQ, web tabanlı bir yönetim arayüzü sunar (varsayılan port: 15672). Bu arayüzden:

  • Exchange, queue ve binding'leri görsel olarak yönetebilir

  • Mesaj oranlarını (message rate) izleyebilir

  • Kuyruk derinliklerini (queue depth) kontrol edebilir

  • Manuel olarak mesaj yayınlayabilir veya kuyruktan mesaj okuyabilirsiniz

Docker ile hızlıca başlatmak için:

docker run -d --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  rabbitmq:3-management
# Management UI: http://localhost:15672 (guest/guest)