RabbitMQ Cluster Kurulumu ve Yüksek Erişilebilirlik

Üretim ortamında tek bir RabbitMQ node’uyla çalışmak, gece 2’de telefon beklemek demektir. Bunu bir kez yaşayan sysadmin, bir daha asla tek node’la production’a çıkmaz. Bu yazıda sıfırdan bir RabbitMQ cluster kurulumunu, Quorum Queue yapılandırmasını ve gerçek anlamda yüksek erişilebilirlik sağlamak için yapmanız gerekenleri adım adım ele alacağız.

Ortam Hazırlığı ve Gereksinimler

Üç node’dan oluşan bir cluster kuracağız. Bunun altında mantıksal bir neden var: RabbitMQ, Raft konsensüs algoritması kullandığı için tek sayıda node’a ihtiyaç duyar. İki node’lu bir cluster, split-brain durumunda karar veremez ve kendini durdurur. Minimum üç node, production için makul bir başlangıç noktasıdır.

Node’larımız şunlar olsun:

  • rabbitmq-01: 192.168.10.11
  • rabbitmq-02: 192.168.10.12
  • rabbitmq-03: 192.168.10.13

İşletim sistemi olarak Ubuntu 22.04 LTS kullanacağız. Her node için önerilen minimum kaynak:

  • CPU: 4 vCPU
  • RAM: 8 GB (RabbitMQ bellek limitini toplam RAM’in %40’ı olarak ayarlar)
  • Disk: 50 GB SSD (Durable queue’lar için disk I/O kritik)
  • Network: Node’lar arası düşük latency, tercihen aynı availability zone

Her üç node’da da /etc/hosts dosyasını düzenleyerek hostname çözümlemesini sağlayın. DNS üzerinden de yapabilirsiniz ama /etc/hosts daha öngörülebilir davranır:

cat >> /etc/hosts << 'EOF'
192.168.10.11 rabbitmq-01
192.168.10.12 rabbitmq-02
192.168.10.13 rabbitmq-03
EOF

Hostname’lerin doğru set edildiğini kontrol edin:

hostnamectl set-hostname rabbitmq-01  # Her node'da kendi adını set edin
hostname -f  # FQDN kontrolü

RabbitMQ Kurulumu

Her üç node’da aynı kurulum adımlarını uygulayacaksınız. RabbitMQ’nun resmi paket deposunu kullanmak, dağıtımın kendi reposunu kullanmaktan çok daha mantıklı. Ubuntu’nun standart reposundaki sürüm genellikle birkaç major version geride kalır.

# Erlang ve RabbitMQ için gerekli bağımlılıklar
apt-get update
apt-get install -y curl gnupg apt-transport-https

# Erlang reposunu ekle (TeamRabbitMQ'nun Erlang paketi önerilir)
curl -1sLf 'https://dl.cloudsmith.io/public/rabbitmq/rabbitmq-erlang/setup.deb.sh' | bash

# RabbitMQ reposunu ekle
curl -1sLf 'https://dl.cloudsmith.io/public/rabbitmq/rabbitmq-server/setup.deb.sh' | bash

# Kurulum
apt-get update
apt-get install -y erlang-base 
    erlang-asn1 
    erlang-crypto 
    erlang-eldap 
    erlang-ftp 
    erlang-inets 
    erlang-mnesia 
    erlang-os-mon 
    erlang-parsetools 
    erlang-public-key 
    erlang-runtime-tools 
    erlang-snmp 
    erlang-ssl 
    erlang-syntax-tools 
    erlang-tftp 
    erlang-tools 
    erlang-xmerl

apt-get install -y rabbitmq-server

Kurulum sonrası servisi başlatıp enable edin:

systemctl enable rabbitmq-server
systemctl start rabbitmq-server
systemctl status rabbitmq-server

Erlang Cookie Senkronizasyonu

Cluster kurulumunun en kritik ve en çok hata yapılan adımı budur. RabbitMQ node’ları birbirleriyle Erlang distributed protocol üzerinden konuşur ve bunun için tüm node’larda aynı Erlang cookie değerinin olması zorunludur. Cookie uyuşmazlığı, node’ların birbirine bağlanamamasına neden olur ve hata mesajları bazen yanıltıcı olabilir.

İlk node’da cookie’yi okuyun:

# rabbitmq-01 üzerinde
cat /var/lib/rabbitmq/.erlang.cookie
# Örnek çıktı: ABCDEFGHIJKLMNOP

Bu değeri diğer node’lara kopyalayın:

# rabbitmq-02 ve rabbitmq-03 üzerinde
systemctl stop rabbitmq-server

# Cookie dosyasını yazın (rabbitmq-01'den kopyaladığınız değeri kullanın)
echo -n "ABCDEFGHIJKLMNOP" > /var/lib/rabbitmq/.erlang.cookie
chmod 400 /var/lib/rabbitmq/.erlang.cookie
chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie

systemctl start rabbitmq-server

Cookie senkronizasyonu yaparken echo -n kullanmak önemli. -n olmadan satır sonu karakteri eklendiği için cookie değeri farklı olur ve node’lar bağlanamaz. Bu hatayı defalarca gördüm, mutlaka dikkat edin.

Cluster’ı Oluşturma

Cookie senkronizasyonundan sonra node’ları cluster’a ekleyebilirsiniz. Bu işlemi rabbitmq-02 ve rabbitmq-03 üzerinde yapacaksınız. rabbitmq-01 referans node olarak kalacak.

rabbitmq-02 üzerinde:

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq-01
rabbitmqctl start_app

rabbitmq-03 üzerinde:

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@rabbitmq-01
rabbitmqctl start_app

Cluster durumunu kontrol edin:

rabbitmqctl cluster_status

Çıktıda üç node’u da görmeli ve hepsinin running nodes listesinde yer almalısınız. Eğer bir node disc yerine ram olarak görünüyorsa ve bu sizin istediğiniz bir şey değilse, --disc parametresiyle join_cluster komutunu tekrar çalıştırabilirsiniz. Genel tavsiyem: production’da tüm node’ları disc node olarak kullanın.

Management Plugin ve İzleme

Management UI olmadan RabbitMQ yönetmek gereksiz yere zorlaştırır. Her node’da plugin’i aktifleştirin:

rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable rabbitmq_management_agent

Varsayılan guest kullanıcısı yalnızca localhost’tan bağlanabilir. Production için ayrı bir admin kullanıcısı oluşturun:

# Admin kullanıcısı oluştur
rabbitmqctl add_user admin 'G3rc3ktenGucluBirSifre!'
rabbitmqctl set_user_tags admin administrator
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

# Guest kullanıcısını silin (güvenlik için)
rabbitmqctl delete_user guest

Management UI’ya http://rabbitmq-01:15672 adresinden erişebilirsiniz. Cluster view’da tüm node’ları göreceksiniz.

Quorum Queue Yapılandırması

Eski klasik mirrored queue yapısı RabbitMQ 3.9’dan itibaren deprecated oldu ve 3.12 itibarıyla kaldırıldı. Quorum Queue, modern ve doğru yaklaşım. Raft tabanlı çalışır, lider seçimi yapar ve veri tutarlılığı konusunda çok daha güvenilirdir.

Quorum Queue oluştururken dikkat etmeniz gereken parametreler:

  • x-queue-type: quorum olarak set edilmeli
  • x-quorum-initial-group-size: Varsayılan cluster boyutunu kullanır, genellikle dokunmayın
  • x-delivery-limit: Mesajın kaç kez yeniden deneneceği, zehirli mesajları önlemek için önemli
# rabbitmqadmin ile quorum queue oluşturma
rabbitmqadmin declare queue 
    name=siparis-kuyrugu 
    durable=true 
    arguments='{"x-queue-type": "quorum", "x-delivery-limit": 5}'

Python istemcisi üzerinden exchange ve queue bind örneği:

import pika

credentials = pika.PlainCredentials('admin', 'G3rc3ktenGucluBirSifre!')
parameters = pika.ConnectionParameters(
    host='rabbitmq-01',
    port=5672,
    credentials=credentials
)

connection = pika.BlockingConnection(parameters)
channel = connection.channel()

# Exchange tanımla
channel.exchange_declare(
    exchange='siparis-exchange',
    exchange_type='direct',
    durable=True
)

# Quorum Queue tanımla
channel.queue_declare(
    queue='siparis-kuyrugu',
    durable=True,
    arguments={
        'x-queue-type': 'quorum',
        'x-delivery-limit': 5
    }
)

# Bind et
channel.queue_bind(
    exchange='siparis-exchange',
    queue='siparis-kuyrugu',
    routing_key='yeni-siparis'
)

connection.close()
print("Queue ve exchange başarıyla oluşturuldu.")

Load Balancer Entegrasyonu

Uygulama katmanından doğrudan node IP’sine bağlanmak, yüksek erişilebilirliğin önündeki en büyük engeldir. Bir node düştüğünde uygulamanız haberdar olmaz ve bağlantı hatası alır. Önlerine bir HAProxy koyarak bu problemi çözeceğiz.

HAProxy kurulumu:

apt-get install -y haproxy

/etc/haproxy/haproxy.cfg konfigürasyonu:

global
    log /dev/log local0
    maxconn 50000
    user haproxy
    group haproxy
    daemon

defaults
    log     global
    mode    tcp
    option  tcplog
    option  dontlognull
    timeout connect 5s
    timeout client  60s
    timeout server  60s

# AMQP load balancing
frontend rabbitmq_frontend
    bind *:5672
    default_backend rabbitmq_backend

backend rabbitmq_backend
    balance roundrobin
    option tcp-check
    server rabbitmq-01 192.168.10.11:5672 check inter 5s rise 2 fall 3
    server rabbitmq-02 192.168.10.12:5672 check inter 5s rise 2 fall 3
    server rabbitmq-03 192.168.10.13:5672 check inter 5s rise 2 fall 3

# Management UI load balancing
frontend rabbitmq_management_frontend
    bind *:15672
    default_backend rabbitmq_management_backend

backend rabbitmq_management_backend
    balance roundrobin
    option httpchk GET /api/health/checks/aliveness
    http-check expect status 200
    server rabbitmq-01 192.168.10.11:15672 check inter 10s rise 2 fall 3
    server rabbitmq-02 192.168.10.12:15672 check inter 10s rise 2 fall 3
    server rabbitmq-03 192.168.10.13:15672 check inter 10s rise 2 fall 3

# HAProxy stats
listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 10s

HAProxy’nin health check için kullandığı /api/health/checks/aliveness endpoint’i, node’un gerçekten sağlıklı olup olmadığını kontrol eder. Basit bir TCP check’ten çok daha güvenilirdir.

Bellek ve Disk Alarmları

RabbitMQ, bellek veya disk eşiği aşıldığında flow control mekanizmasını devreye alır ve publisher’ları bloklar. Bu davranışı anlamak ve doğru eşikleri ayarlamak, production’da sürprizleri önler.

/etc/rabbitmq/rabbitmq.conf dosyasını oluşturun veya düzenleyin:

cat > /etc/rabbitmq/rabbitmq.conf << 'EOF'
# Cluster adı
cluster_name = production-rabbitmq

# Bellek eşiği - toplam RAM'in %40'ı (varsayılan)
vm_memory_high_watermark.relative = 0.4

# Disk eşiği - en az 2GB boş alan
disk_free_limit.absolute = 2GB

# Heartbeat - bağlantı kopuklarını hızlı tespit
heartbeat = 60

# Network partition handling
cluster_partition_handling = pause_minority

# Bağlantı başına maksimum kanal sayısı
channel_max = 2047

# Log seviyesi
log.console.level = info
log.file.level = info
log.file = /var/log/rabbitmq/rabbit.log
EOF

cluster_partition_handling = pause_minority ayarı kritik. Split-brain durumunda azınlıkta kalan taraf kendini durdurur. Bu, veri tutarsızlığı yaşamak yerine hizmet vermemeyi tercih etmek anlamına gelir. Production’da bu davranış genellikle doğru tercihtir.

Konfigürasyon değişikliği sonrası servisi yeniden başlatın:

systemctl restart rabbitmq-server

Monitoring ve Alerting

Prometheus + Grafana kombinasyonu RabbitMQ izleme için standart haline geldi. RabbitMQ, Prometheus formatında metrik sunan built-in bir plugin’e sahip:

rabbitmq-plugins enable rabbitmq_prometheus

Plugin aktifleştirildikten sonra http://rabbitmq-01:15692/metrics adresinde metriklere ulaşabilirsiniz.

Prometheus scrape konfigürasyonu:

scrape_configs:
  - job_name: 'rabbitmq'
    static_configs:
      - targets:
          - 'rabbitmq-01:15692'
          - 'rabbitmq-02:15692'
          - 'rabbitmq-03:15692'
    scrape_interval: 15s

İzlemeniz gereken kritik metrikler:

  • rabbitmq_queue_messages: Kuyrukta bekleyen mesaj sayısı, anormal yükselme consumer sorunu işareti
  • rabbitmq_queue_messages_unacked: Acknowledge edilmemiş mesajlar, consumer’ın yavaşladığının göstergesi
  • rabbitmq_node_mem_used: Bellek kullanımı, watermark’a yaklaşırsa alarm
  • rabbitmq_node_disk_free: Disk alarmı tetiklenmeden önce müdahale etmek için
  • rabbitmq_connections: Bağlantı sızdıran uygulama kodunu tespit etmek için

Grafana için RabbitMQ resmi dashboard’u dashboard ID 10991 ile import edebilirsiniz. Sıfırdan yazmak yerine bunu özelleştirmek çok daha verimli.

Cluster Bakım Operasyonları

Cluster’daki bir node’u bakım amacıyla devre dışı bırakmak istediğinizde sıralamanın önemi var. Node’u direkt kapatmak yerine önce draining yapın:

# Node'u bakım moduna al (RabbitMQ 3.8+)
rabbitmqctl drain

# Bakım modundan çık
rabbitmqctl revive

Rolling upgrade yaparken bir node’da işlem tamamlanmadan diğerine geçmeyin. Her upgrade sonrası cluster durumunu kontrol edin:

# Cluster sağlık kontrolü
rabbitmqctl cluster_status
rabbitmq-diagnostics check_running
rabbitmq-diagnostics check_local_alarms

# Node'ların senkronize olduğunu kontrol et
rabbitmqctl list_queues name messages mirror_pids synchronised_slave_pids

Quorum Queue’ların lider dağılımını kontrol etmek de iyi bir pratik. Tüm liderler tek bir node’da toplanmışsa yük dengesizliği oluşur:

rabbitmqctl list_queues name leader members

Gerçek Dünya Senaryosu: Node Kaybı ve Recovery

Cluster çalışırken rabbitmq-02 tamamen çöksün. Bu durumda ne olur?

Quorum Queue, kalan iki node (rabbitmq-01 ve rabbitmq-03) üzerinde çoğunluğu koruyarak çalışmaya devam eder. HAProxy, rabbitmq-02‘nin health check’inin başarısız olduğunu fark eder ve trafiği kalan node’lara yönlendirir. Uygulamanız kesintisiz çalışmaya devam eder.

rabbitmq-02 geri geldiğinde otomatik olarak cluster’a yeniden katılır ve Quorum Queue’lar üzerindeki veriler senkronize edilir. Manuel müdahaleye gerek yoktur.

Ancak node uzun süre çevrimdışı kaldıysa (örneğin birkaç gün), geri döndükten sonra senkronizasyon süreci yoğun disk I/O yaratabilir. Bu durumda düşük trafik saatlerinde recovery planlamak mantıklıdır.

# Node geri döndükten sonra durumu kontrol et
rabbitmqctl cluster_status

# Quorum queue'ların sağlık durumu
rabbitmq-diagnostics check_running
rabbitmqctl list_quorum_queues

Sonuç

RabbitMQ cluster kurulumu teknik olarak karmaşık değil, ama her adımın neden yapıldığını anlamadan yapılan kurulumlar production’da sürpriz yaratır. Erlang cookie senkronizasyonu, Quorum Queue’ya geçiş, load balancer entegrasyonu ve doğru partition handling stratejisi, gerçek anlamda yüksek erişilebilirlik için birbirini tamamlayan parçalar.

Özellikle eski kaynaklarda hala mirrored queue örnekleri görüyorum. Eğer RabbitMQ 3.8 ve üzerini kullanıyorsanız, Quorum Queue’ya geçin. Daha az konfigürasyon, daha iyi tutarlılık garantileri ve aktif geliştirme. Mirrored queue artık bir geçmişe ait.

Son olarak: monitoring olmadan cluster kurmak, emniyet kemeri takmadan araba kullanmak gibi. Prometheus entegrasyonunu ve anlamlı alarm eşiklerini baştan yapılandırın. Bir sorun oluştuğunda logları didik didik aramak yerine Grafana dashboard’unuza bakıp durumu anında görmek, gece 2’deki o telefonu almamak demektir.

Bir yanıt yazın

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