RabbitMQ Quorum Queue Yapılandırması ve Klasik Kuyruktan Geçiş Rehberi

Production ortamında mesaj kaybı yaşamak, gecenin 3’ünde pager’ın çalması demektir. RabbitMQ’nun klasik kuyruklarını kullanan sistemlerde node çöktüğünde mesajların buharlaşması, pek çok ekibin acı tecrübeyle öğrendiği bir gerçek. İşte bu yüzden RabbitMQ 3.8 ile hayatımıza giren Quorum Queue yapısı, ciddi bir üretim ortamı için artık tercih değil zorunluluk haline geldi. Bu yazıda klasik kuyruktan quorum queue’ya nasıl geçeceğini, nelere dikkat etmen gerektiğini ve production’da karşılaşabileceğin senaryoları ele alacağız.

Quorum Queue Nedir, Neden Önemli?

Klasik RabbitMQ kuyruklarında replikasyon, mirrored queue mekanizmasıyla sağlanıyordu. Bu yapıda master node düşünce slave node master oluyordu, ama bu geçiş süreci sağlıklı değildi. Split-brain durumlarında mesaj kaybı veya duplicate mesaj üretimi ciddi sorunlara yol açıyordu.

Quorum Queue, Raft consensus algoritması üzerine inşa edilmiş bir yapı. Basit anlatımla, bir mesajın kalıcı sayılabilmesi için cluster’daki node’ların çoğunluğunun (quorum) onaylaması gerekiyor. Örneğin 3 node’lu bir cluster’da en az 2 node onaylamalı. 5 node’lu bir cluster’da en az 3.

Bu yapının sana kazandırdıkları:

  • Mesaj garantisi: Node çöküşlerinde mesaj kaybı yaşamazsın
  • Lider seçimi: Raft sayesinde otomatik ve tutarlı leader election
  • Poison message yönetimi: Sürekli hata veren mesajlar için delivery-limit özelliği
  • Daha az konfigürasyon: Mirrored queue’nun karmaşık policy yapısına gerek yok
  • At-least-once delivery: Mesajlar en az bir kez işlenir garantisi

Dezavantajları da görmezden gelemeyiz tabii:

  • Disk kullanımı klasik kuyruğa göre daha fazla
  • Lazy mode varsayılan olarak aktif, bu yüzden memory kullanımı farklı davranır
  • Geçici (transient) mesajları desteklemez, tüm mesajlar persistent sayılır
  • TTL bazlı özellikler kısıtlı

Cluster Hazırlığı

Quorum queue için en az 3 node’lu bir RabbitMQ cluster’ına ihtiyacın var. Tek node veya 2 node’lu yapılarda quorum elde edemezsin.

Önce mevcut cluster durumunu kontrol et:

# Cluster durumunu görüntüle
rabbitmqctl cluster_status

# Node'ların sağlık durumunu kontrol et
rabbitmq-diagnostics check_running
rabbitmq-diagnostics check_local_alarms

# Disk ve memory alarm durumunu gör
rabbitmqctl status | grep -A5 "alarms"

Eğer cluster’ın yoksa ve test ortamı kuruyorsan, Docker Compose ile hızlıca 3 node’lu bir yapı ayağa kaldırabilirsin:

# docker-compose.yml
version: '3.8'
services:
  rabbitmq1:
    image: rabbitmq:3.12-management
    hostname: rabbitmq1
    environment:
      RABBITMQ_ERLANG_COOKIE: "SECRETCOOKIE123"
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: adminpass
    ports:
      - "15672:15672"
      - "5672:5672"

  rabbitmq2:
    image: rabbitmq:3.12-management
    hostname: rabbitmq2
    environment:
      RABBITMQ_ERLANG_COOKIE: "SECRETCOOKIE123"
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: adminpass
    ports:
      - "15673:15672"
      - "5673:5672"

  rabbitmq3:
    image: rabbitmq:3.12-management
    hostname: rabbitmq3
    environment:
      RABBITMQ_ERLANG_COOKIE: "SECRETCOOKIE123"
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: adminpass
    ports:
      - "15674:15672"
      - "5674:5672"
# Container'ları ayağa kaldır
docker-compose up -d

# rabbitmq2 ve rabbitmq3'ü cluster'a ekle
docker exec rabbitmq2 rabbitmqctl stop_app
docker exec rabbitmq2 rabbitmqctl join_cluster rabbit@rabbitmq1
docker exec rabbitmq2 rabbitmqctl start_app

docker exec rabbitmq3 rabbitmqctl stop_app
docker exec rabbitmq3 rabbitmqctl join_cluster rabbit@rabbitmq1
docker exec rabbitmq3 rabbitmqctl start_app

# Cluster durumunu doğrula
docker exec rabbitmq1 rabbitmqctl cluster_status

Quorum Queue Oluşturma

Cluster hazır olduğunda quorum queue oluşturmak oldukça basit:

# Management API ile quorum queue oluştur
curl -u admin:adminpass -X PUT http://localhost:15672/api/queues/%2F/my-quorum-queue 
  -H "Content-Type: application/json" 
  -d '{
    "durable": true,
    "arguments": {
      "x-queue-type": "quorum",
      "x-quorum-initial-group-size": 3,
      "x-delivery-limit": 5,
      "x-message-ttl": 86400000
    }
  }'

Ya da rabbitmqadmin CLI aracıyla:

# rabbitmqadmin ile quorum queue oluştur
rabbitmqadmin declare queue 
  name=order-processing-queue 
  durable=true 
  arguments='{"x-queue-type":"quorum","x-quorum-initial-group-size":3,"x-delivery-limit":10}'

# Kuyruğu listele ve tipini doğrula
rabbitmqadmin list queues name type state members

Önemli argümanlar:

  • x-queue-type: quorum olarak set edilmeli, bu zorunlu
  • x-quorum-initial-group-size: Başlangıçta kaç replica oluşturulacağı, genellikle cluster büyüklüğüne eşit
  • x-delivery-limit: Bir mesaj kaç kez redelivery olabilir, poison message kontrolü için kritik
  • x-message-ttl: Mesaj yaşam süresi (millisecond cinsinden)
  • x-dead-letter-exchange: Delivery limit dolunca mesajın gideceği exchange

Policy ile Quorum Queue Yönetimi

Production ortamında kuyruğu tek tek argümanlarla oluşturmak yerine policy kullanmak çok daha yönetilebilir bir yapı sunar:

# Tüm "qq-" prefix'li kuyruklara quorum policy uygula
rabbitmqctl set_policy quorum-policy 
  "^qq-" 
  '{"x-queue-type":"quorum","x-delivery-limit":10}' 
  --apply-to queues 
  --priority 10

# Policy'leri listele
rabbitmqctl list_policies

# Belirli bir vhost için policy oluştur
rabbitmqctl set_policy -p production quorum-policy 
  "^critical-" 
  '{"x-queue-type":"quorum","x-quorum-initial-group-size":5,"x-delivery-limit":3}' 
  --apply-to queues

Klasik Kuyruktan Geçiş Süreci

İşte asıl zorlu kısım burası. Var olan bir klasik kuyruğu doğrudan quorum queue’ya dönüştüremezsin. RabbitMQ bu ikisini tamamen farklı kuyruk tipleri olarak değerlendiriyor. Geçiş için birkaç farklı strateji mevcut.

Strateji 1: Blue-Green Geçiş (Önerilen)

Bu yöntem en güvenli yaklaşım. Önce yeni quorum queue’yu oluşturuyorsun, sonra trafiği yavaş yavaş buraya yönlendiriyorsun.

# 1. Adım: Yeni quorum queue oluştur
rabbitmqadmin declare queue 
  name=order-queue-v2 
  durable=true 
  arguments='{"x-queue-type":"quorum","x-delivery-limit":5}'

# 2. Adım: Exchange binding'i yeni kuyruğa ekle
# (Eski binding'i hemen silme, önce yeni consumer'ları test et)
rabbitmqadmin declare binding 
  source=order-exchange 
  destination=order-queue-v2 
  routing_key=order.new

# 3. Adım: Eski kuyruktaki mesajları boşalt ve izle
rabbitmqadmin get queue=order-queue count=100

# 4. Adım: Eski binding'i kaldır
rabbitmqadmin delete binding 
  source=order-exchange 
  destination=order-queue 
  routing_key=order.new
  
# 5. Adım: Eski kuyruk boşaldığında sil
rabbitmqadmin delete queue name=order-queue

Strateji 2: Shovel Plugin ile Mesaj Aktarımı

Eğer eski kuyrukta mesajlar birikmiş durumdaysa ve hizmet kesintisi yapamıyorsan, Shovel plugin en iyi arkadaşın olur:

# Shovel plugin'i aktif et
rabbitmq-plugins enable rabbitmq_shovel
rabbitmq-plugins enable rabbitmq_shovel_management

# Dynamic shovel oluştur - mesajları eski kuyruktan yeni quorum queue'ya taşı
rabbitmqctl set_parameter shovel migrate-orders 
  '{"src-protocol":"amqp091",
    "src-uri":"amqp://admin:adminpass@localhost",
    "src-queue":"order-queue",
    "dest-protocol":"amqp091",
    "dest-uri":"amqp://admin:adminpass@localhost",
    "dest-queue":"order-queue-v2",
    "src-delete-after":"queue-length",
    "ack-mode":"on-confirm"}'

# Shovel durumunu izle
rabbitmqctl shovel_status

# Aktarım tamamlandığında shovel'ı kaldır
rabbitmqctl clear_parameter shovel migrate-orders

Dead Letter Queue Yapılandırması

Quorum queue’nun en güçlü özelliklerinden biri, delivery limit aşıldığında mesajları otomatik olarak dead letter exchange’e yönlendirmesi:

# Önce dead letter exchange oluştur
rabbitmqadmin declare exchange 
  name=dlx-exchange 
  type=direct 
  durable=true

# Dead letter queue oluştur (bu klasik queue olabilir, DLQ için quorum şart değil)
rabbitmqadmin declare queue 
  name=dead-letter-queue 
  durable=true

# DLX exchange ile dead letter queue'yu bağla
rabbitmqadmin declare binding 
  source=dlx-exchange 
  destination=dead-letter-queue 
  routing_key=failed-messages

# Ana quorum queue'yu DLX konfigürasyonuyla oluştur
curl -u admin:adminpass -X PUT http://localhost:15672/api/queues/%2F/order-queue 
  -H "Content-Type: application/json" 
  -d '{
    "durable": true,
    "arguments": {
      "x-queue-type": "quorum",
      "x-delivery-limit": 5,
      "x-dead-letter-exchange": "dlx-exchange",
      "x-dead-letter-routing-key": "failed-messages"
    }
  }'

Monitoring ve İzleme

Quorum queue’ların sağlığını izlemek için birkaç kritik metric var:

# Kuyruk detaylarını görüntüle
rabbitmqctl list_queues 
  name 
  type 
  state 
  messages 
  messages_ready 
  messages_unacknowledged 
  leader 
  members 
  online

# Quorum queue'lara özel durum bilgisi
rabbitmqctl list_queues 
  name 
  type 
  leader 
  members 
  online 
  --formatter pretty_table 2>/dev/null || 
rabbitmqctl list_queues name type leader members online

# Node başına kuyruk istatistiklerini çek
rabbitmq-diagnostics quorum_status order-queue

# Prometheus endpoint üzerinden metric çek (rabbitmq_prometheus plugin aktifse)
curl -s http://localhost:15692/metrics | grep -E "rabbitmq_queue_messages|rabbitmq_quorum"

Prometheus ve Grafana kullanıyorsan, şu metrikleri mutlaka dashboard’una ekle:

  • rabbitmq_quorum_log_commit_latency_seconds: Raft log commit süresi
  • rabbitmq_queue_messages_ready: İşlenmeye hazır mesaj sayısı
  • rabbitmq_queue_messages_unacked: Acknowledge edilmemiş mesaj sayısı
  • rabbitmq_quorum_log_snapshot_chunk_size: Snapshot boyutu

Gerçek Dünya Senaryosu: E-ticaret Sipariş Sistemi

Diyelim ki bir e-ticaret platformunda sipariş işleme sistemini yönetiyorsun. Günlük 100.000 sipariş akıyor, Black Friday’de bu 500.000’e çıkıyor. Mevcut yapında mirrored classic queue kullanıyorsun ve geçen ay node çöküşünde 2.000 siparişi kaybettin. Müşteri şikayetleri, geri ödemeler, itibar kaybı… Şimdi quorum queue’ya geçme zamanı.

Geçiş planın şöyle olabilir:

# 1. Mevcut durumu belgele
rabbitmqctl list_queues name messages consumers durable > queue-snapshot-$(date +%Y%m%d).txt

# 2. Test için yeni quorum queue oluştur
rabbitmqadmin declare queue 
  name=order-queue-qq 
  durable=true 
  arguments='{"x-queue-type":"quorum","x-quorum-initial-group-size":3,"x-delivery-limit":5,"x-dead-letter-exchange":"dlx-exchange"}'

# 3. Canary deployment: Yeni consumer'ları önce %10 trafikle test et
# Application tarafında feature flag ile kontrol et

# 4. Trafiği yavaş artır: %10 -> %25 -> %50 -> %100
# Her aşamada error rate ve latency'yi izle

# 5. Eski kuyruktaki mesajlar bitince shovel ile kalanları taşı
rabbitmqctl set_parameter shovel final-migration 
  '{"src-protocol":"amqp091",
    "src-uri":"amqp://",
    "src-queue":"order-queue",
    "dest-protocol":"amqp091",
    "dest-uri":"amqp://",
    "dest-queue":"order-queue-qq",
    "src-delete-after":"queue-length",
    "ack-mode":"on-confirm",
    "src-prefetch-count":100}'

# 6. Migration tamamlandıktan sonra temizle
rabbitmqctl clear_parameter shovel final-migration
rabbitmqadmin delete queue name=order-queue
rabbitmqadmin declare queue 
  name=order-queue 
  durable=true 
  arguments='{"x-queue-type":"quorum","x-delivery-limit":5}'

Performans Tuning

Quorum queue varsayılan ayarlarla iyi çalışır ama production’da birkaç şeyi ayarlamak performansı ciddi artırır:

# rabbitmq.conf dosyasına eklenecek ayarlar
cat >> /etc/rabbitmq/rabbitmq.conf << 'EOF'

# Quorum queue için Raft ayarları
raft.wal_max_size_bytes = 536870912
raft.segment_max_entries = 65536

# Consumer timeout (uzun süreli işler için artır)
consumer_timeout = 1800000

# Disk free space alarm eşiği (quorum queue disk kullanımı yüksek)
disk_free_limit.relative = 2.0

# Channel max
channel_max = 2047
EOF

# Servisi yeniden başlat
systemctl restart rabbitmq-server

# Ayarların uygulandığını doğrula
rabbitmqctl environment | grep raft

Sık Karşılaşılan Sorunlar

Quorum queue minority durumu: Cluster’da 3 node’tan 2’si düşerse, quorum kuyrukları yeni mesaj almayı reddeder. Bu kasıtlı bir davranış, tutarlılık için kullanılabilirliği feda eder.

# Minority durumunu kontrol et
rabbitmqctl list_queues name state leader members online 
  | grep -v "running"

# Zorla leadership transferi (dikkatli kullan!)
rabbitmqctl quorum_queue force_checkpoint order-queue

Yüksek disk kullanımı: Quorum queue tüm mesajları diske yazar. Segment dosyalarını düzenli compaction ile küçültebilirsin:

# Kuyruk compaction durumunu izle
rabbitmq-diagnostics quorum_status order-queue

# Manuel olarak raft log compaction tetikle
rabbitmqctl eval 'rabbit_quorum_queue:wal_force_roll_over(node()).'

Consumer prefetch ayarı: Quorum queue’larda yüksek prefetch değeri mesaj birikimini engeller ama memory kullanımını artırır. Genellikle 10-50 arası bir değer dengeli çalışır.

Sonuç

Quorum queue’ya geçiş bir gecede olan bir şey değil. Önce test ortamında cluster kur, klasik kuyruk davranışını ve quorum queue davranışını karşılaştır. Node çökme senaryolarını simüle et, mesaj kaybı yaşanmadığını doğrula. Sonra production’da blue-green stratejisiyle yavaş yavaş geçiş yap.

Özetlemek gerekirse:

  • Mesaj güvenilirliği kritikse quorum queue zorunlu
  • En az 3 node’lu cluster şart, 5 node daha iyi
  • Mirrored queue policy’lerini kaldır, quorum queue ile çakışır
  • Dead letter queue konfigürasyonunu ihmal etme, poison message sistemleri mahveder
  • Monitoring’i geçiş öncesi kur, geçiş sonrası kör uçma
  • Disk kapasitesini klasik kuyruğa göre 2-3x fazla planla

RabbitMQ 3.12 ve sonrasında mirrored queue deprecated statüsünde ve bir sonraki major sürümde kaldırılacak. Dolayısıyla bu geçişi ertelemek sadece gelecekte daha büyük bir kriz yaratıyor. Şimdi kontrollü geçiş yapman, ileride zorla yapılacak bir geçişten çok daha az riskli.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir